home *** CD-ROM | disk | FTP | other *** search
- /* --------------------------------------------------------------------------
- * Copyright 1992 by Forschungszentrum Informatik (FZI)
- *
- * You can use and distribute this software under the terms of the licence
- * you should have received along with this program.
- * If not or if you want additional information, write to
- * Forschungszentrum Informatik, "STONE", Haid-und-Neu-Strasse 10-14,
- * D-7500 Karlsruhe 1, Germany.
- * --------------------------------------------------------------------------
- */
- // **************************************************************************
- // Module Mapping 9/8/90 Jochen Alt (ja)
- // modified : 24/10/91 (bs)
- // modified : 22/11/91 (ja)
- // **************************************************************************
- // implements methods of classes: Mapping, sos_Map_node
- // **************************************************************************
-
- #include "agg_err.h"
- #include "trc_agg.h"
- #include "sys.h"
- #include "Mapping.h"
- #include "agg_sos.h"
-
- // erweiterbares Hash-Verfahren mit leichten Modifikationen
- // Quelle : Datenbankhandbuch Seite 247
- // siehe externe Dokumentation
-
- #define get_key_based_on_equal() get_role1_based_on_equal()
- #define get_info_based_on_equal() get_role2_based_on_equal()
- #define set_key_based_on_equal(b) set_role1_based_on_equal(b)
- #define set_info_based_on_equal(b) set_role2_based_on_equal(b)
-
- inline int absolute(int d) { return (d>0)?d:-d; }
-
- const sos_Offset NIL=0;
-
- // Da psm direkt benutzt wird, wird ein Datentyp benoetigt, der
- // anstelle der Objekte abgespeichert wird. Dies ist ein object_save_t,
- // der augenblicklich als sos_Typed_id definiert ist. Die beiden Operatoren,
- // die object_save_t in sos_Object und umgekehrt konvertieren, sind
- // make_object_save und make_Object
- // **************************************************************************
- object_save_t make_object_save (sos_Object o)
- // **************************************************************************
- // nimm das sos_Object o, bastle daraus ein object_save, und
- // liefere es in os zurueck
- { sos_Typed_id tpid = o.typed_id();
- object_save_t os;
- bcopy_from_sos_Typed_id(&tpid,&os);
- return os;
- }
-
- // **************************************************************************
- sos_Object make_Object (object_save_t &os)
- // **************************************************************************
- // nimm den object_save os, mache daraus ein sos_Object und liefere es zurueck
- { sos_Typed_id tpid;
- bcopy_to_sos_Typed_id(&tpid,&os);
- return sos_Object::make(tpid);
- }
-
- /*
- Abhaengig von sos_Bool:list_cursor gibt es zwei Versionen eines Mappings:
- 1. Version: list_cursor = FALSE
- Die Cursoroperatoren sind nur auf einem statischen Mapping
- definiert. Wird ein Objekt eingefuegt, so kan sich die Cursor-Reihenfolge
- voellig veraendern. Damit ist ein sinnvoller Umgang mit Cursorn nur auf
- einem sich nicht veraendernden Mapping moeglich. Sobald etwas eingefuegt
- oder geloescht wird, sind die Cursor zu schliessen und neu von vorne
- zu beginnen. Die Reihenfolge der Objekte ist durch die
- Reihenfolge in der Hashtabelle definiert, also fuer den Benutzer rein
- zufaellig. In dieser Version braucht ein Eintrag 36 Byte (= 2x sos_Object
- und ein Hashwert a 4 byte)
- 2. Version : list_cursor = TRUE
- Die Cursor-Operatoren koennen auch an einem dynamischen Mapping gleich-
- zeitig ausgefuehrt werden. Die einzelnen Eintraege sind miteinander
- doppelt verkettet, ein Einfuegen erfolgt am Anfang der Liste. Ein Eintrag
- braucht damit 36+2x16 = 68 Byte (zusaetzlich ein Vorwaerts und ein
- Rueckwaertszeiger). Damit werden die Prozeduren remove_at, insert_before
- und insert_after sinnvoll. In der Implementierung wird auf einer Seite
- die struct-Komponente list, bestehend aus den beiden Verweisen
- zusaetzlich abgespeichert.
-
- In Funktionen, die ein Objekt zurueckliefern sollen, jedoch keines zum Liefern
- haben, wird my_no_object als Ruckgabeparameter von benutzt. Weiterhin dient
- my_no_object als Ende-der-Liste Marke im ersten und letzten Element des
- Mappings. Kurzum, my_no_object ist ein Mapping- lokales NO_OBJECT, und dient
- dazu, das Einfuegen von NO_OBJECT zu ermoeglichen. Stattdessen kann man eben
- my_no_object nicht einfuegen. Faktisch wird my_no_object immer mit dem
- augenblicklich benutzten Mapping initialisiert, so dass ein Mapping nicht in
- sich selbst eingefuegt werden kann. Dieses wird entsprechend abgefangen.
- */
-
- #define PAGE_SIZE(list_cursor) \
- (list_cursor?page_size_with_list: page_size_without_list)
-
- // max_page_entries = die maximale Anzahl an Eintraegen auf einer Seite
- #define MAX_PAGE_ENTRIES(list_cursor) \
- (list_cursor? max_page_entries_with_list: max_page_entries_without_list)
-
- // aus einer gegebenen Position in der Hashtabelle und der lokalen Tiefe
- // der zugehoerigen Seitenliste kann die erste Position in der Hashtabelle
- // berechnet werden, die auf diesselbe Seitenliste zeigt.
- #define FIRST_LINK(ht_pos,local_depth) \
- ((LSHIFT(1,local_depth)-1) BITAND ht_pos)
-
- /* *********** Implementierung von sos_Map_node *********************
- Ein sos_Map_node enthaelt nur die Komponente sos_Object:key_val, die
- dasjenige Objekt angibt, auf das der Cursor augenblicklich zeigt.
- Ein sos_Map_node ist eindeutig einem Cursor zugeordnet und liegt
- in dessen Container. Ist der Cursor ungueltig, so ist die Komponente
- Cursor->get_key_val() == NO_OBJECT, andernfalls zeigt sie auf einen
- sos_Map_node. Also wird beim Starten auf einem Mapping mit Inhalt ein
- sos_Map_node erzeugt und dem Cursor zugeordnet, beim Verlassen des
- letzten gueltigen Elements wird der sos_Map_node wieder geloescht.
- */
-
-
- // **************************************************************************
- sos_Int hash_id (sos_Object o)
- // **************************************************************************
- // benutzt die Adresse des Objektes, um daraus eine Zahl zu basteln
-
- // Offsets liegen nur auf durch 8 teilbaren Addressen
- // => die ersten 3 Bit sind nutzlos, wird sie weg.
- // Ist das Objekt aber keine Klassen-Instanz, sondern
- // ein externes Objekt (z.B. sos_Int,sos_Char),
- // so wird der Offset benutzt, indem der Wert steht.
- { sos_Int h = o.offset();
- if (o.container() != UNUSED_CONTAINER)
- h = RSHIFT(h,3) BITXOR sos_Int(o.container());
-
- return h;
- } // ** hash_id **
-
-
- // **************************************************************************
- ht_entry_t read_ht_entry(sos_Container ct,
- sos_Offset ht_offset,
- sos_Int ht_pos)
- // **************************************************************************
- { union {sos_Offset dummy;
- char mem [HT_ENTRY_SIZE];} u;
- ct.read(ht_offset+ht_pos*HT_ENTRY_SIZE, HT_ENTRY_SIZE, &u);
- ht_entry_t ht_entry;
- bcopy_to_sos_Offset(&ht_entry.page_list_offset,&u.mem[0]);
- bcopy_to_sos_Char(&ht_entry.local_depth, &u.mem[SOS_OFFSET_SIZE] );
- return ht_entry;
- } // ** read_ht_entry **
-
- // **************************************************************************
- void write_ht_entry(sos_Container ct,
- sos_Offset ht_offset,
- sos_Int ht_pos,
- ht_entry_t ht_entry)
- // **************************************************************************
- { union {sos_Offset dummy;
- char mem [HT_ENTRY_SIZE];} u;
-
- bcopy_from_sos_Offset(&ht_entry.page_list_offset, &u.mem[0]);
- bcopy_from_sos_Char(&ht_entry.local_depth, &u.mem[SOS_OFFSET_SIZE]);
- ct.write(ht_offset+ht_pos*HT_ENTRY_SIZE, HT_ENTRY_SIZE, &u);
- } // ** write_ht_entry **
-
-
- // **************************************************************************
- page_header_t read_page_header(sos_Container ct, sos_Offset page_offset)
- // **************************************************************************
- { union {sos_Offset dummy;
- char mem [PAGE_HEADER_SIZE];} u;
-
- page_header_t page_header;
- ct.read (page_offset, PAGE_HEADER_SIZE, &u);
- bcopy_to_sos_Offset(&page_header.next_page, &u.mem[0]);
- bcopy_to_sos_Char(&page_header.pages, &u.mem[SOS_OFFSET_SIZE]);
- bcopy_to_sos_Char(&page_header.entries_on_last_page,
- &u.mem[SOS_OFFSET_SIZE+CHAR_SIZE]);
-
- return page_header;
- } // ** read_page_header **
-
- // **************************************************************************
- void write_page_header(sos_Container ct,
- sos_Offset page_offset,
- page_header_t& page_header)
- // **************************************************************************
- { union {sos_Offset dummy;
- char mem [PAGE_HEADER_SIZE];} u;
-
- bcopy_from_sos_Offset(&page_header.next_page,&u.mem[0]);
- bcopy_from_sos_Char(&page_header.pages,&u.mem[SOS_OFFSET_SIZE]);
- bcopy_from_sos_Char(&page_header.entries_on_last_page,
- &u.mem[SOS_OFFSET_SIZE+CHAR_SIZE]);
- ct.write (page_offset, PAGE_HEADER_SIZE, &u);
- } // ** write_page_header **
-
-
- /*
- Eine Seitenliste besteht aus einzelnen Seiten des Typs page_t, wobei
- diese durch Vorwaertszeiger verkettet sind. Auf jeder Seite befindet sich
- ein Seitenkopf mit den Angaben:
-
- sos_Char pages;
- => Anzahl der Seiten in der Seitenliste
- sos_Char entries_on_last_page;
- => Eintraege auf der letzten Seite, alle anderen Seite sind
- voll, d.h. sie haben max_page_entries Eintraege. Diese Angabe
- wird nur auf der ersten Seite verwaltet, auf den restlichen
- Seiten ist entries_on_last_page undefiniert.
- sos_Offset next_page;
- => Verweis auf die naechste Seite, bei der letzten Seite
- undefiniert.
- */
-
-
- // **************************************************************************
- void destroy_page_list(sos_Bool list_cursor,
- sos_Container ct,
- sos_Offset page_offset,
- sos_Int no_of_pages)
- // **************************************************************************
- // deallokiere im Container ct die Seitenliste bestehend aus den
- // Typen page_t, wobei die erste zu deallokierende Seite auf page_offset
- // liegt. Insgesamt sind no_of_pages Seiten zu loeschen.
- { sos_Offset act_page_offset = page_offset;
- sos_Offset next_page_offset;
- for (sos_Int i=1;i<=no_of_pages;i++)
- { // Lese zuerst naechsten Verweis, bevor die Seite deallokiert wird
- page_header_t page_header = read_page_header(ct, act_page_offset);
- next_page_offset = page_header.next_page;
-
- ct.deallocate(act_page_offset,PAGE_SIZE(list_cursor));
- act_page_offset = next_page_offset;
- }
- } // ** destroy_page_list **
-
-
- // **************************************************************************
- void read_page( sos_Bool list_cursor,
- sos_Container ct,
- sos_Offset page_offset,
- sos_Int no_of_entries,
- page_t& page)
- // **************************************************************************
- // Lese Seite ab sos_Offset page_offset. Es werden no_of_entries
- // Eintraege eingelesen.
- { err_assert((no_of_entries>=0 AND no_of_entries<=MAX_PAGE_ENTRIES(list_cursor)),
- "Mapping:read_page_entry::internal Error");
- page.page_header = read_page_header(ct,page_offset);
- union {sos_Typed_id dummy;
- char mem [MAX_PAGE_SIZE];} u;
- ct.read(page_offset+PAGE_HEADER_SIZE, no_of_entries*ENTRY_SIZE,&u);
- char *ptr = u.mem;
- for (int i = 0;i<no_of_entries;i++)
- { bcopy_to_sos_Typed_id(&page.entry[i].key,ptr);
- ptr += SOS_TYPED_ID_SIZE;
- bcopy_to_sos_Typed_id(&page.entry[i].info,ptr);
- ptr += SOS_TYPED_ID_SIZE;
- bcopy_to_sos_Int(&page.entry[i].hash_value,ptr);
- ptr += INT_SIZE;
- }
-
- if (list_cursor)
- { // Lese die Vorgaenger und Nachfolger Verweise
- ptr = u.mem;
- ct.read(page_offset+add_list_pos, no_of_entries*LIST_SIZE, &u);
- for (int i = 0; i < no_of_entries; i++)
- { bcopy_to_sos_Typed_id(&page.list[i].pred,ptr);
- ptr += SOS_TYPED_ID_SIZE;
- bcopy_to_sos_Typed_id(&page.list[i].succ,ptr);
- ptr += SOS_TYPED_ID_SIZE;
- }
- }
- } // ** read_page **
-
- // **************************************************************************
- sos_Int read_page( sos_Bool list_cursor,
- sos_Container ct,
- page_header_t first_page_header,
- ht_entry_t ht_entry,
- sos_Int page_no,
- page_t& page)
- // **************************************************************************
- // Lese die page_no.te Seite, auf die der Hashtabelleneintrag ht_entry
- // zeigt, wobei der Seitenkopf der ersten Seite schon unter
- // first_page_header bekannt ist.
- { sos_Offset page_offset = ht_entry.page_list_offset;
- page.page_header = first_page_header;
-
- // Durchlaufe Seitenliste bis zur richtigen Seite
- for (sos_Int no = 1; no < page_no; no++)
- { if (no >1)
- page.page_header = read_page_header(ct,page_offset);
- page_offset =page.page_header.next_page;
- }
- sos_Int entries = (page_no < first_page_header.pages)?
- MAX_PAGE_ENTRIES(list_cursor):
- first_page_header.entries_on_last_page;
- read_page(list_cursor, ct, page_offset, entries, page);
-
- return entries;
- } // ** read_page **
-
- // **************************************************************************
- void read_page_entry(sos_Bool list_cursor,
- sos_Container ct,
- sos_Int page_offset,
- sos_Int entry_no,
- page_t& page)
- // **************************************************************************
- // Lese auf der Seite auf page_offset den entry_no.ten Eintrag in page
- { err_assert((entry_no>=0 AND entry_no<=MAX_PAGE_ENTRIES(list_cursor)),
- "Mapping::read_page_entry::internal Error");
- union {sos_Typed_id dummy;
- char mem[ENTRY_SIZE];} u; // note: ENTY_SIZE > LIST_SIZE
-
- ct.read( page_offset+PAGE_HEADER_SIZE+entry_no*ENTRY_SIZE,
- ENTRY_SIZE,&u);
- bcopy_to_sos_Typed_id(&page.entry[entry_no].key,&u.mem[0]);
- bcopy_to_sos_Typed_id(&page.entry[entry_no].info,&u.mem[SOS_TYPED_ID_SIZE]);
- bcopy_to_sos_Int(&page.entry[entry_no].hash_value,
- &u.mem[SOS_TYPED_ID_SIZE+SOS_TYPED_ID_SIZE]);
-
- if (list_cursor)
- { ct.read( page_offset+add_list_pos+entry_no*LIST_SIZE,
- LIST_SIZE,&u);
- bcopy_to_sos_Typed_id(&page.list[entry_no].pred,&u.mem[0]);
- bcopy_to_sos_Typed_id(&page.list[entry_no].succ,
- &u.mem[SOS_TYPED_ID_SIZE]);
- }
- } // ** read_page_entry **
-
- // **************************************************************************
- void write_page(sos_Bool list_cursor,
- sos_Container ct,
- sos_Offset page_offset,
- sos_Int no_of_entries,
- page_t& page)
- // **************************************************************************
- // Schreibe die Seite page mit no_of_entries Eintraegen
- // an die Stelle page_offset
- { write_page_header(ct,page_offset,page.page_header);
- err_assert((no_of_entries>=0 AND no_of_entries<=MAX_PAGE_ENTRIES(list_cursor)),
- "Mapping::write_page::internal Error");
-
- union {sos_Typed_id dummy;
- char mem [MAX_PAGE_SIZE];} u;
- char *ptr = u.mem;
- for (int i = 0; i < no_of_entries; i++)
- { bcopy_from_sos_Typed_id(&page.entry[i].key,ptr);
- ptr += SOS_TYPED_ID_SIZE;
- bcopy_from_sos_Typed_id(&page.entry[i].info,ptr);
- ptr += SOS_TYPED_ID_SIZE;
- bcopy_from_sos_Int(&page.entry[i].hash_value,ptr);
- ptr += INT_SIZE;
- }
- ct.write(page_offset+PAGE_HEADER_SIZE, no_of_entries*ENTRY_SIZE,&u);
-
- if (list_cursor)
- { ptr = u.mem;
- for (int i = 0; i < no_of_entries; i++)
- { bcopy_from_sos_Typed_id(&page.list[i].pred,ptr);
- ptr += SOS_TYPED_ID_SIZE;
- bcopy_from_sos_Typed_id(&page.list[i].succ,ptr);
- ptr += SOS_TYPED_ID_SIZE;
- }
- ct.write(page_offset+add_list_pos, LIST_SIZE*no_of_entries, &u);
- }
- } // ** write_page **
-
- // **************************************************************************
- void write_page_entry(sos_Bool list_cursor,
- sos_Container ct,
- sos_Int page_offset,
- sos_Int entry_no,
- page_t& page)
- // **************************************************************************
- // Schreibe auf der Seite page den einzelnen Eintrag Nr entry_no
- // auf die Platte, der Seitenanfang beginnt bei page_offset.
- { err_assert((entry_no>=0 AND entry_no<=MAX_PAGE_ENTRIES(list_cursor)),
- "Mapping::write_page::internal Error");
- union {sos_Typed_id dummy;
- char mem[ENTRY_SIZE];} u; // note: ENTY_SIZE > LIST_SIZE
-
- bcopy_from_sos_Typed_id(&page.entry[entry_no].key,&u.mem[0]);
- bcopy_from_sos_Typed_id(&page.entry[entry_no].info,
- &u.mem[SOS_TYPED_ID_SIZE]);
- bcopy_from_sos_Int(&page.entry[entry_no].hash_value,
- &u.mem[SOS_TYPED_ID_SIZE+SOS_TYPED_ID_SIZE]);
-
- ct.write( page_offset+PAGE_HEADER_SIZE+entry_no*ENTRY_SIZE,
- ENTRY_SIZE,&u);
- if (list_cursor)
- { bcopy_from_sos_Typed_id(&page.list[entry_no].pred,&u.mem[0]);
- bcopy_from_sos_Typed_id(&page.list[entry_no].succ,
- &u.mem[SOS_TYPED_ID_SIZE]);
- ct.write( page_offset+add_list_pos+entry_no*LIST_SIZE, LIST_SIZE,&u);
- }
- } // ** write_page_entry **
-
- // search_page_for_key__F8sos_BoolR6page_tiiG10sos_Object
- // **************************************************************************
- sos_Int search_page_for_key(sos_Bool key_based_on_equal,
- page_t& page,
- sos_Int entries,
- sos_Int org_hash_value,
- sos_Object key)
- // **************************************************************************
- // durchsucht die Seite page mit entries Eintraegen nach dem sos_Object key,
- // das den Hashwert org_hash_value besitzt. Wird es gefunden, wird seine
- // Position in der Seite geliefert, ansonsten -1.
- { T_PROC("search_page_for_key");
- TT(agg_M, T_ENTER);
-
- sos_Bool found = FALSE;
- for (sos_Int i=0;
- ((i<entries) AND (NOT found));
- i++)
- { if (page.entry[i].hash_value == org_hash_value)
- { sos_Object o = make_Object(page.entry[i].key);
- if (agg_same_entity(o, key, key_based_on_equal, EQ_STRONG))
- { found = TRUE;
- TT(agg_M, T_LEAVE);
- return i;
- }
- }
- }
-
- TT(agg_M, T_LEAVE);
- return -1;
- } // ** search_page_for_key **
-
- // **************************************************************************
- sos_Offset new_page_list(sos_Container ct, sos_Bool list_cursor)
- // **************************************************************************
- // allokiere eine neue Seitenliste und liefere deren sos_Offset zurueck
- { T_PROC("new_page_list");
- TT(agg_L, T_ENTER);
-
- sos_Offset new_page_offset = ct.allocate(PAGE_SIZE(list_cursor));
- page_header_t page_header;
- page_header.entries_on_last_page = 0;
- page_header.pages = 1;
- write_page_header(ct,new_page_offset, page_header);
-
- TT(agg_L, T_LEAVE);
- return new_page_offset;
- } // ** new_page_list **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::write_succ_pred(
- sos_Container ct,
- sos_Bool key_based_on_equal,
- sos_Bool list_cursor,
- sos_Object key,
- sos_Bool write_succ,
- sos_Object succ_pred)
- // **************************************************************************
- // Schreibe in den Vorgaeger bzw. Nachfolger von key succ_pred.
- // Ob Vor oder Nachgaenger ausgewaehlt wird, wird durch write_succ
- // geregelt. write_succ == TRUE schreibt succ_pred in den
- // Nachfolgerzeiger von key, ansonsten in den Vorgaengerzeiger von key.
- { T_PROC("Mapping::write_succ_pred");
- TT(agg_M, T_ENTER);
- sos_Object my_no_object = self;
- if (my_no_object == key)
- { TT(agg_M, T_LEAVE);
- return;
- }
-
- sos_Int org_hash_value = absolute((key_based_on_equal)?
- key.hash_value():hash_id(key));
- sos_Int ht_pos = org_hash_value MOD self.get_ht_entries();
- ht_entry_t ht_entry = read_ht_entry(ct,self.get_ht_offset(),ht_pos);
-
- sos_Offset page_offset = ht_entry.page_list_offset;
- page_header_t first_page_header = read_page_header(ct, page_offset);
- sos_Int pages = first_page_header.pages;
- sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
-
- sos_Int pos = -1; // entspricht "nicht gefunden"
- sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
- page_t page;
- for (sos_Int page_no = 1;
- (page_no<=pages) AND (pos == -1);
- page_no++)
- { if (page_no == pages)
- entries_on_page = entries_on_last_page;
-
- read_page(TRUE, ct, page_offset, entries_on_page, page);
- sos_Int pos = search_page_for_key ( key_based_on_equal,page,
- entries_on_page,
- org_hash_value, key );
- if (pos == -1)
- page_offset = page.page_header.next_page;
- else
- { // Objekt gefunden
- if (write_succ)
- page.list[pos].succ = make_object_save(succ_pred);
- else
- page.list[pos].pred = make_object_save(succ_pred);
- write_page_entry(TRUE, ct,page_offset,pos, page);
- }
- }
- TT(agg_M, T_LEAVE);
- } // ** Mapping::write_succ_pred **
-
-
- // **************************************************************************
- sos_Offset increase_page_list( sos_Bool list_cursor,
- sos_Container ct,
- sos_Offset first_page_offset,
- page_header_t& first_page_header,
- sos_Offset last_page_offset)
- // **************************************************************************
- // Eine Seitenliste, die an der Stelle ht_pos an der Hashtabelle
- // angehaengt ist, wird um eine Seite erweitert. diese Seite wird
- // hinten angehaengt. Ein Verweis auf die bisher letzte Seite
- { T_PROC("increase_page_list");
- TT(agg_M, T_ENTER);
-
- sos_Offset new_page_offset = ct.allocate(PAGE_SIZE(list_cursor));
-
- // Eigentlich sollte der Fall der Seitenlisten gaenzlich vermieden
- // werden. Wird nun eine Seitenliste tatsaechlich ueber 126 Seiten
- // gross, so ist entweder die Statistik fehlerhaft, oder es
- // sind tatsaechlich mehr als 3225 Eintraege mit demselben Hashwert im
- // Mapping. Diese Faelle fuehren zum Absturz, da die Variable, die die
- // Seiten in einer Seitenliste zaehlt, ein char ist. Ansich ist eine
- // solche Konstellation jedoch nicht vorstellbar.
- if (first_page_header.pages >= 126)
- err_raise(err_SYS, "statistical Error","Mapping:insert");
-
- first_page_header.pages++;
- first_page_header.entries_on_last_page = 0;
-
- // Existierte bisher nur eine Seite ?
- if (first_page_header.pages == 2)
- first_page_header.next_page = new_page_offset;
- else
- { // Es gab schon mehr als eine Seite, der erste Seitenheader und
- // der Header der bisher letzten Seite muss geschrieben werden
- page_header_t last_page_header;
- last_page_header.next_page = new_page_offset;
- write_page_header(ct,last_page_offset, last_page_header);
- }
- write_page_header(ct,first_page_offset, first_page_header);
-
- TT(agg_M, T_LEAVE);
- return new_page_offset;
- } // ** Mapping::increase_page_list
-
- /*
- Um zu entscheiden, ob die Hashtabelle geschrumpft werden kann, muss bekannt
- sein, ob es Seitenlisten gibt, auf die nur ein HT-Eintrag verweist. Falls ja,
- ist ein Schrumpfen nicht moeglich. Da beim Teilen und Splitten einer Seite
- die lokale Tiefe veraendert wird, muss fuer jede moegliche lokale Tiefe
- die Anzahl der Verweise gespeichert werden, da beim Splitten 2 Seiten
- mit hoeheren lokalen Tiefen dazukommen und eine mit einer niedrigeren weg-
- faellt.
- Es gibt also einen von Hand allokierten Platz, auf dessen Anfang
- get_no_of_pages_offset() zeigt. In den ersten 4 Byte davon steht die Anzahl
- der Seitenlisten mit lokaler Tiefe 0 , in den naechsten 4 Byte die Anzahl mit
- lokaler Tiefe 1 etc. bis MAX_GLOBAL_DEPTH.
- */
-
- // **************************************************************************
- sos_Bool no_single_referenced_pages(sos_Container ct,
- sos_Offset no_of_pages_offset,
- sos_Int global_depth)
- // **************************************************************************
- // liefert TRUE, falls es keine Seitenliste gibt, die von der Hashtabelle
- // nur von einem einzigen Verweis referenziert wird. Dies wird anhand
- // der Zaehler festgestellt, die fuer jede lokale Tiefe zaehlen, wieviel
- // Seitenlisten es mit dieser lokalen Tiefe gibt. Die Seitenlisten, die
- // nur von einem Verweis referenziert werden, zeichnen sich durch
- // lokale Tiefe == globale Tiefe aus.
- { sos_Int entry;
- union {sos_Int dummy;
- char mem [INT_SIZE];} u;
- // lese die Anzahl der Verweise auf Seitenlisten der lokalen
- // Tiefe global_depth
- ct.read(no_of_pages_offset+INT_SIZE*global_depth,INT_SIZE,&u);
- bcopy_to_sos_Int(&entry,&u);
- return sos_Bool (entry == 0);
- } // ** Mapping::no_single_referenced_pages **
-
- // **************************************************************************
- void add_no_of_pages(sos_Container ct,
- sos_Offset no_of_pages_offset,
- sos_Int local_depth,
- sos_Int value)
- // **************************************************************************
- // zaehle zu der Anzahl von Verweisen auf eine Seitenliste mit der
- // lokalen Tiefe local_depth value dazu.
- { sos_Int entry;
- union {sos_Int dummy;
- char mem [INT_SIZE];} u;
-
- sos_Int offset = no_of_pages_offset+INT_SIZE*local_depth;
- ct.read(offset, INT_SIZE, &u);
- bcopy_to_sos_Int(&entry,&u);
- entry += value;
- bcopy_from_sos_Int(&entry,&u);
- ct.write(offset, INT_SIZE, &u);
- } // ** add_no_of_page **
-
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::insert_in_page_list (
- sos_Container ct,
- sos_Bool key_based_on_equal,
- sos_Bool list_cursor,
- sos_Offset page_list_offset,
- sos_Int org_hash_value,
- sos_Object key, sos_Object info,
- sos_Object pred, sos_Object succ)
- // **************************************************************************
- // traegt einen Eintrag in eine Seitenliste ein und ersetzt
- // geg. einen alten. Auf der Seitenliste muss Platz sein
- { T_PROC("Mapping::insert_in_page_list");
-
- page_t page;
- sos_Offset page_offset = page_list_offset;
-
- // Befindet sich der key bereits auf der Seite, so wird er durch
- // den neuen Eintrag ersetzt. Schaue also nach
-
- sos_Int pos = -1; // entspricht "nicht gefunden"
- sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
-
- page.page_header = read_page_header(ct,page_offset);
-
- page_header_t first_page_header = page.page_header;
- sos_Int pages = first_page_header.pages;
- sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
- for (sos_Int page_no=1;
- (page_no <= pages) AND (pos == -1);
- page_no++)
- { if (page_no == pages)
- entries_on_page = entries_on_last_page;
- read_page(list_cursor, ct,page_offset, entries_on_page, page);
- pos = search_page_for_key (key_based_on_equal, page,
- entries_on_page, org_hash_value,key);
- if ((pos == -1) AND (page_no < pages))
- page_offset = page.page_header.next_page;
- }
-
- // Falls der Eintrag ersetzt wird, so wird er an diese
- // Stelle eingesetzt. Ansonsten wird er auf der
- // letzten Seite eingetragen und die H-Tabelle korrigiert
-
- sos_Int write_pos = pos;
- if (pos == -1)
- { // Eintrag nicht gefunden, also schreibe ihn auf die letzte Seite.
- // Da die gesamte Liste durchgegangen wurde, ist page_offset
- // die Adresse der letzten Seite.
-
- // korrigiere Seitenheader der ersten Seite
- first_page_header.entries_on_last_page++;
- write_page_header(ct,page_list_offset,first_page_header);
-
- write_pos = entries_on_page;
- self.set_cardinality(self.get_cardinality() + 1);
- }
-
- page.entry[write_pos].hash_value = org_hash_value;
- // Falls der Key existiert wird er nicht nochmal eingetragen,
- // sondern nur der Entity ersetzt
- if (write_pos != pos)
- page.entry[write_pos].key = make_object_save(key);
- page.entry[write_pos].info = make_object_save(info);
-
- // Schreibe die Liste evt auf die Seite zurueck
- if (pos == -1)
- { if (list_cursor)
- { // schreibe in die Liste succ und pred
- page.list[write_pos].succ = make_object_save(succ);
- page.list[write_pos].pred = make_object_save(pred);
- // aktualisiere den Vorwaertszeiger von pred und den
- // Rueckwaertszeiger von succ
- self.write_succ_pred
- (ct, key_based_on_equal, list_cursor, pred, TRUE, key);
- self.write_succ_pred
- (ct, key_based_on_equal, list_cursor, succ, FALSE, key);
-
- if (self.get_cardinality() == 1)
- { // erstes Element wird eingefuegt
- self.set_first_object(key);
- self.set_last_object(key);
- }
- else
- { if (self.get_first_object() == succ)
- self.set_first_object(key);
- if (self.get_last_object() == pred)
- self.set_last_object(key);
- }
- }
-
- // schreibe den Eintrag auf der Seite zurueck
- write_page_entry(list_cursor, ct,page_offset, write_pos, page);
- }
- else
- // Der Eintrag war bereits vorhanden, nur der Entity wurde geaendert
- // schreibe den Eintrag auf der Seite zurueck
- write_page_entry(list_cursor, ct,page_offset, write_pos, page);
-
- TT(agg_M, T_LEAVE);
- } // ** Mapping::insert_in_page_list **
-
-
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::split_page(sos_Container ct,
- sos_Bool list_cursor,
- sos_Offset page_list_offset,
- sos_Char par_local_depth,
- sos_Int org_hash_value,
- sos_Int nec_local_depth)
- // **************************************************************************
- // Eine Seitenliste wird solange gesplittet, bis der Seitenliste
- // die neue lokale Tiefe nec(cessary)_local_depth zugeordnet wird.
- // Saemtliche Seitenteilungen vor der letzten sind Seitenteilungen
- // ohne Bewegungen von Objekten, denn wuerden Objekte bewegt,
- // wuerde Platz geschaffen und somit waere nec_local_depth kleiner.
- { T_PROC("Mapping::split_page");
- TT(agg_M, T_ENTER);
-
- sos_Int global_depth = self.get_global_depth();
- sos_Offset no_of_pages_offset = self.get_no_of_pages_offset();
- sos_Offset ht_offset = self.get_ht_offset();
-
- sos_Int max_page_entries = MAX_PAGE_ENTRIES(list_cursor);
- // Teile die Seitenliste sooft wie noetig, d.h. allokiere neue
- // Seiten und biege die richtigen HT-Eintraege auf diese
- // Seiten um
- for (;par_local_depth <nec_local_depth;)
- { // erzeuge neue leere Seite
- ht_entry_t new_ht_entry;
- new_ht_entry.page_list_offset = new_page_list(ct, list_cursor);
- sos_Int local_depth = par_local_depth;
- sos_Int new_local_depth = ++par_local_depth;
- new_ht_entry.local_depth = new_local_depth;
- self.set_no_of_page_lists(self.get_no_of_page_lists() + 1);
- self.set_no_of_pages(self.get_no_of_pages() + 1);
-
- add_no_of_pages(ct,no_of_pages_offset,local_depth,-1);
- add_no_of_pages(ct,no_of_pages_offset,new_local_depth,2);
-
- // biege alle Eintraege der HT mit gesetztem
- // new_local_depth.ten Bit auf die neue Seite um
-
- // Wie lautet der der neuen Seite zugeordnete Hash-Wert-Teil ?
- // Nimm den alten Hash-Teil
- sos_Int old_hash_value_part = org_hash_value BITAND
- (LSHIFT(1,local_depth)-1);
-
- // Laufe alle Indexe durch, bei denen ein Verweis
- // auf die zu teilende Seitenliste steht. Das sind
- // 2^(global_depth-local_depth) Stueck.
-
- // Die Verweise werden abwechselnd belassen und umgebogen.
- // Da auf der alten Seitenliste die ersten nec_local_depth
- // Bit gleich sind, wird so begonnen, dass die alte Seitenliste
- // immer noch von der gleichen Stelle der
- // H-Tabelle erreicht wird (new_link)
- sos_Bool new_link = FALSE; // starte bei alter Seitenliste
- if ((org_hash_value BITAND LSHIFT(1,local_depth)) != 0)
- new_link = TRUE; // starte bei leerer Seite
-
- // wo ist der erste Verweis auf diese Seitenliste ?
- for (sos_Int k = 0;k<LSHIFT(1,global_depth-local_depth); k++)
- { // verschiebe Laufindex k an richtige Position
- // vor dem Wert der Seite
- sos_Int j = LSHIFT(k,local_depth);
- // addiere den Hash-Teil der Seite dazu
- j = j BITOR old_hash_value_part;
-
- if (new_link)
- // Dieser Eintrag muss auf die neue
- // leere Seite umgebogen werden
- write_ht_entry(ct, ht_offset, j, new_ht_entry);
- else
- { // Dieser Eintrag verbleibt,
- // lediglich die lokale Tiefe wird geaendert
- ht_entry_t tmp_ht_entry = read_ht_entry(ct, ht_offset, j);
- tmp_ht_entry.local_depth ++;
- write_ht_entry(ct,ht_offset,j, tmp_ht_entry);
- }
- new_link = (sos_Bool) (NOT new_link);
- }
- }
-
- // Da nur die letzte Seitenteilung hierbei beteiligt ist,
- // muessen also Seiteneintraege der alten Seitenliste
- // auf die bis jetzt leere Partnerseite.
- // Berechne Hash-Teil der alten Seitenliste
- sos_Int hash_value_part = org_hash_value BITAND
- (LSHIFT(1,nec_local_depth)-1);
- // invertiere das nec_local_depth.te Bit => Partnerseite
- sos_Int ht_partner_pos = hash_value_part BITXOR
- LSHIFT(1,nec_local_depth-1);
-
- // Lese den Offset der Partnerseite
- ht_entry_t ht_partner_entry = read_ht_entry(ct,ht_offset,ht_partner_pos);
- // Also: Die Eintraege kommen von ht_entry.page_list_offset
- // nach ht_partner_entry.page_list_offset
-
- // Gehe die alte Seitenliste durch und schiebe jeden Seiteneintrag,
- // dessen Hashwert ein anderes nec_local_depth.tes Bit aufweist
- // als in org_hash_value, auf die neue Seitenliste
-
- sos_Offset old_page_offset = page_list_offset;
- sos_Offset read_page_offset = old_page_offset;
- sos_Offset new_page_offset = ht_partner_entry.page_list_offset;
- sos_Int bit = LSHIFT(1,nec_local_depth-1);
- sos_Int should_be_bit = org_hash_value BITAND bit;
-
- page_t old_page;
- page_header_t old_page_header = read_page_header(ct,old_page_offset);
- old_page.page_header = old_page_header;
- sos_Int old_entry_no = 0;
- sos_Int old_page_no = 1;
- sos_Bool add_old_page = FALSE;
-
- page_t new_page;
- sos_Int new_entry_no = 0;
- sos_Int new_page_no = 1;
-
- page_header_t new_page_header = read_page_header(ct,new_page_offset);
- new_page.page_header = new_page_header;
-
- page_t r_page;
- page_header_t r_page_header = read_page_header(ct,read_page_offset);
-
- sos_Int no_of_pages = self.get_no_of_pages();
- for (sos_Int read_page_no=1;
- read_page_no <= r_page_header.pages;
- read_page_no++)
- { sos_Int read_entries = (r_page_header.pages > read_page_no)?
- max_page_entries:r_page_header.entries_on_last_page;
- read_page(list_cursor, ct,read_page_offset, read_entries, r_page);
- read_page_offset = r_page.page_header.next_page;
-
- // Gehe die alte Seite durch und kopiere die passenden Eintraege
- // auf die neue Seite.
- for (sos_Int read_no=0;read_no<read_entries;read_no++)
- { if ((r_page.entry[read_no].hash_value BITAND bit) !=should_be_bit)
- { // gesetztes Bit => Eintrag auf neue Seite
-
- // Ist neue Seite schon vollstaendig beschrieben ?
- if (new_entry_no == max_page_entries)
- { // Falls die neue Seite bereits voll ist, erweitere Liste
- sos_Offset last_page =
- increase_page_list(list_cursor, ct,
- ht_partner_entry.page_list_offset,
- new_page_header, new_page_offset);
-
- no_of_pages++;
- new_page.page_header = new_page_header;
- new_page.page_header.next_page = last_page;
-
- // und schreibe die volle Seite aus
- write_page(list_cursor, ct, new_page_offset,
- max_page_entries, new_page);
-
- new_entry_no = 0;
- new_page_offset = last_page;
- new_page_no++;
-
- }
- new_page.entry[new_entry_no] = r_page.entry[read_no];
- // Falls list_cursor == FALSE schadet
- // die folgende Zeile nichts
- new_page.list[new_entry_no++] = r_page.list[read_no];
- }
- else
- { // Ist die alte Seite schon vollstaendig beschrieben ?
- if (old_entry_no == max_page_entries)
- { // Ja, schreibe alte volle Seite aus
- write_page(list_cursor, ct,
- old_page_offset, max_page_entries, old_page);
-
- old_page_no++;
- old_page_offset = old_page.page_header.next_page;
-
- // Lese den Vorwaertsverweis der naechsten Seite
- if (old_page_no < old_page_header.pages)
- old_page.page_header=read_page_header(ct,old_page_offset);
-
- old_entry_no = 0;
- }
- old_page.entry[old_entry_no] = r_page.entry[read_no];
- // Falls list_cursor == FALSE schadet
- // die folgende Zeile nichts
- old_page.list[old_entry_no++] = r_page.list[read_no];
- }
- }
- }
-
- self.set_no_of_pages(no_of_pages);
-
- // Falls eine neue Seite noch nicht ausgeschrieben ist, tue dies
- if (new_entry_no > 0)
- { new_page.page_header.entries_on_last_page = new_entry_no;
- new_page.page_header.pages = new_page_no;
- write_page(list_cursor, ct,new_page_offset, new_entry_no, new_page);
- }
-
- // Korrigiere Seitenheader der ersten neuen Seite
- new_page_header.entries_on_last_page = new_entry_no;
- new_page_header.pages = new_page_no;
-
- // Schreibe evt. den Seitenheader
- if ((new_page_header.pages > 1) OR (new_entry_no == 0))
- write_page_header(ct,ht_partner_entry.page_list_offset,new_page_header);
-
-
- // Falls eine alte Seite noch nicht ausgeschrieben wurde, tue dies
- if (old_entry_no > 0)
- { old_page.page_header.entries_on_last_page = old_entry_no;
- old_page.page_header.pages = old_page_no;
- write_page(list_cursor, ct,old_page_offset, old_entry_no, old_page);
- }
-
- // Falls die alte Seitenliste eine volle Liste ist, lasse eine
- // leere Seite dranhaengen, da auf der alten Seitenliste ein
- // neuer Eintrag erfolgen soll.
- if (old_entry_no == max_page_entries)
- { old_entry_no = 0;
- old_page_no++;
- add_old_page = TRUE;
- }
-
- // Korrigiere Seitenheader der ersten alten Seite
- old_page_header.entries_on_last_page = old_entry_no;
- old_page_header.pages = old_page_no;
-
- // Schreibe evt. alten Seitenheader
- if ((old_page_header.pages > 1) OR (old_entry_no == 0))
- write_page_header(ct,page_list_offset, old_page_header);
-
- // Gebe den Rest der alten Seitenliste frei
- if (old_page_no < r_page_header.pages)
- { destroy_page_list(list_cursor, ct, old_page.page_header.next_page,
- r_page_header.pages-old_page_no);
- self.set_no_of_pages(no_of_pages - (r_page_header.pages - old_page_no));
- }
- TT(agg_M, T_LEAVE);
- } // ** Mapping::split_page **
-
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::increase_hash_table()
- // **************************************************************************
- // erweitere die gesamte Hash-Tabelle, d.h. allokiere
- // doppelt soviel Platz wie jetzt belegt wird, kopiere
- // die alte Hash-Tabelle in die erste Haelfte und danach
- // in die zweite Haelfte. => Auf jede Seite
- // existieren zwei Verweise. Wirf die alte Hashtabelle weg
- { T_PROC("Mapping::increase_hash_table");
- TT(agg_M, T_ENTER);
- sos_Container ct = self.container();
- sos_Int old_ht_entries = self.get_ht_entries();
- sos_Int old_ht_size = old_ht_entries*HT_ENTRY_SIZE;
- sos_Offset new_ht_offset = ct.allocate(old_ht_size*2);
-
- // kopiere bisherige Hashtabelle zweimal
- // hintereinander in den neu allokierten Platz
- ct.copy(self.get_ht_offset(), old_ht_size, ct, new_ht_offset);
- ct.copy(self.get_ht_offset(), old_ht_size, ct, new_ht_offset+old_ht_size);
-
- // Wirf alte Hash-tabelle weg
- ct.deallocate(self.get_ht_offset(), old_ht_size);
-
- // markiere die Neue
- self.set_ht_offset(new_ht_offset);
- self.set_ht_entries(old_ht_entries * 2);
- self.set_global_depth(self.get_global_depth() + 1);
- TT(agg_M, T_LEAVE);
- } // ** Mapping::increase_hash_table **
-
- // increase_ht_structur__F8sos_Booliiiiii
- // **************************************************************************
- sos_Bool increase_ht_structur(sos_Bool list_cursor,
- sos_Int global_depth,
- sos_Int ht_entries,
- sos_Int no_of_pages,
- sos_Int length,
- sos_Int local_depth,
- sos_Int nec_local_depth)
- // **************************************************************************
- // entscheidet, ob wegen eines Seitenueberlaufs die HT-Struktur
- // vergoessert werden soll, oder an die Seitenliste eine Seite
- // angehaengt wird.
- {
- T_PROC("increase_ht_structur");
- TT(agg_M, T_ENTER);
-
- // Falls die HT nicht vergroessert werden muesste, sondern
- // eine Seitenteilung reichen wuerde, plaediere immer fuer die
- // Erweiterung der HT
- if (global_depth >= nec_local_depth)
- { TT(agg_M, T_LEAVE)
- return TRUE;
- }
-
- // Berechne den Platzbedarf bei Vergroesserung der HT-Struktur
- sos_Int page_size = PAGE_SIZE(list_cursor);
- sos_Int ht_memory; // Bei HT-Erweiterung
- sos_Int pl_memory; // Bei Seitenlisten Erweiterung
-
- // Bei normaler Speicherausnutzung, d.h. Jede Seite ist
- // zur Haelfte gefuellt, gibt die Kennzahl 100, sonst > 100
- // Ist die Ausnutzung besser, gilt Kennzahl < 100
-
- // Bedarf der jetzigen Hashtabelle
- sos_Int ht_use = ht_entries*HT_ENTRY_SIZE;
-
- // Bedarf der jetzigen saemtlichen Seiten
- sos_Int page_lists_use = no_of_pages*page_size;
-
- // Berechne den Speicher, der beim Erweitern der HT-Struktur
- // zusaetzlich benoetigt wird
-
- // Fuer jedes Splitten kommt eine Seite dazu
- sos_Int increasing_use = (nec_local_depth-local_depth)*page_size;
- // Fuer das Erweitern der HT kommt immer die bisherige Groesse dazu
- increasing_use += (LSHIFT(1,nec_local_depth) - LSHIFT(1,global_depth))
- *HT_ENTRY_SIZE;
-
- sos_Int ht_memory_used = ht_use + page_lists_use + increasing_use;
- // Bei der Alternative der Seitenliste kommt nur eine Seite dazu;
- sos_Int pl_memory_used = ht_use + page_lists_use + page_size;
-
- // Berechne den optimalen Platzbedarf. Er ergibt sich durch
- // zu drei/viertel gefuellte Seiten, wobei jeder Verweis auf genau
- // eine Seite zeigt.=> Berechne Anzahl der noetigen Seiten = Verweise,
- // plumitiziere mit Platzbedarf
- sos_Int opt_entries = MAX_PAGE_ENTRIES(list_cursor)*3/4;
- sos_Int opt_memory_used = (page_size + HT_ENTRY_SIZE)*
- length/opt_entries;
-
- ht_memory = (ht_memory_used*100) / opt_memory_used;
- pl_memory = (pl_memory_used*100) / opt_memory_used;
-
-
- // Berechne die Kennzahl der Zeiteffizienz
- // Es wird die durchschnittliche Laenge einer Seitenliste berechnet
- // Falls keine Seitenlisten existieren, so ist die Effizienz
- // optimal. Die HT-Erweiterung ist in diesem Sinne optimal, auch wenn
- // durch fruehere Seitenlisten die Effizienz nicht 1000 entspricht,
- // ist der einzige moegliche Weg dorthin die HT-Erweiterung.
-
- sos_Int ht_eff = 100;
- sos_Int pl_eff = 100*(no_of_pages+1)/ht_entries;
-
-
- // Jetzt kommt die Entscheidung: Beide Kennzahlen
- // werden gleich gewichtet und verglichen
- sos_Bool result = FALSE;
- if ((ht_memory + ht_eff) <= (pl_memory + pl_eff))
- result = TRUE;
-
- TT(agg_M, T_LEAVE);
- return result;
- } // ** Mapping::increase_ht_structur **
-
-
- // **************************************************************************
- sos_Int neccessary_local_depth(sos_Bool list_cursor,
- sos_Container ct,
- sos_Bool key_based_on_equal,
- sos_Offset page_list_offset,
- sos_Char local_depth,
- sos_Offset& last_page_offset,
- sos_Int org_hash_value,
- sos_Object key)
- // **************************************************************************
- // Es wird berechnet, welche lokale Tiefe eine volle Seitenliste
- // plus dem einzufuegenden Objekt haben muesste, damit mindestens
- // ein Seiten Eintrag abgespalten
- // werden koennte. Oder: Es wird berechnet, bis zu welchem
- // Bit im Hash-Wert nicht mehr alle Seiteneintraege gleich sind
- // Wird dagegen ein Eintrag gefunden, der durch den neuen Eintrag
- // ersetzt wuerde, so wird dieselbe lokale Tiefe zurueckgeliefert
- { T_PROC("neccessary_local_depth");
- TT(agg_M, T_ENTER);
-
- sos_Int hash_value = org_hash_value;
- sos_Int nec_local_depth = MAX_GLOBAL_DEPTH;
- sos_Offset page_offset = page_list_offset;
-
- page_header_t first_page_header;
- first_page_header = read_page_header(ct, page_list_offset);
- sos_Int pages = first_page_header.pages;
- sos_Int entries_on_last_page = first_page_header.entries_on_last_page;
- sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
- // Durchlaufe alle Seiten
- for (sos_Int page_no=1;
- (page_no<=pages);
- page_no++)
- { // Diese Schleife darf nicht vorher abgebrochen werden, da
- // last_page_offset als Ausgabeparameter erwartet wird
-
- page_t page;
- if (page_no == pages)
- entries_on_page = entries_on_last_page;
- read_page(list_cursor, ct, page_offset,entries_on_page, page);
-
- last_page_offset = page_offset;
- page_offset = page.page_header.next_page;
-
- // Durchlaufe alle Eintraege auf dieser Seite
- for (sos_Int entry_no = 0;
- (entry_no < entries_on_page);
- entry_no++)
- { sos_Int tmp_hash_value = page.entry[entry_no].hash_value;
-
- if (org_hash_value == tmp_hash_value)
- { sos_Object o = make_Object(page.entry[entry_no].key);
- if (agg_same_entity (key, o,key_based_on_equal, EQ_STRONG))
- { // das Objekt wuerde dieses Objekt ersetzen, also
- // keine Erhoehung der lokalen Tiefe notwendig
- TT(agg_M, T_LEAVE);
- return local_depth;
- }
- }
- // Ab dem wievielten Bit unterscheiden sich der bisherige
- // Hashwert und der aktuelle Eintrag ?
- sos_Int diff_hash_value = hash_value BITXOR tmp_hash_value;
-
- // Die Bits der lokalen Tiefe sind auf alle Faelle gleich,
- // also rechne erst ab local_depth+1;
- for (sos_Int i = local_depth+1;
- i<=nec_local_depth;
- i++)
- if ((RSHIFT(diff_hash_value, i-1) BITAND 1) == 1)
- nec_local_depth = i++;
- }
- }
-
- TT(agg_M, T_LEAVE);
- return nec_local_depth;
- } // ** Mapping::neccessary_local_depth *
-
- // insert_in_list__30_sos_Object_sos_Object_MappingR12sos_Typed_idG10sos_ObjectN32
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::insert_in_list
- (sos_Object key, sos_Object info,
- sos_Object pred, sos_Object succ)
- // **************************************************************************
- // fuegt einen Eintrag ein und setzt ihn, falls list_cursor == TRUE
- // in die durch pred und succ gegebenene Reihenfolge
- { T_PROC("Mapping::insert_in_list");
- TT(agg_M, T_ENTER);
-
- // Ist das Mapping leer, so existiert noch keine Hashtabelle
- if (self.get_ht_entries() == 0)
- self.init_table();
-
- sos_Container ct = self.container();
- sos_Bool key_based_on_equal = self.get_key_based_on_equal();
- sos_Bool list_cursor = self.get_list_cursor();
- sos_Int org_hash_value = absolute((key_based_on_equal)?
- key.hash_value():hash_id(key));
- sos_Int ht_pos = org_hash_value MOD self.get_ht_entries();
- sos_Offset ht_offset = self.get_ht_offset();
- ht_entry_t ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
-
- page_header_t page_header = read_page_header(ct,ht_entry.page_list_offset);
-
- // Ist die Seitenliste aufgefuellt ?
- if (page_header.entries_on_last_page < MAX_PAGE_ENTRIES(list_cursor))
- // Nein, es ist noch Platz
- self.insert_in_page_list(ct, key_based_on_equal, list_cursor,
- ht_entry.page_list_offset, org_hash_value,
- key, info, pred, succ);
- else
- { // Die Seitenliste ist voll. Entweder wird die HT erweitert,
- // oder die Seitenliste wird um eine Seite vergroessert.
- sos_Offset last_page =0;
- sos_Int nec_local_depth =
- neccessary_local_depth( list_cursor, ct, key_based_on_equal,
- ht_entry.page_list_offset,
- ht_entry.local_depth,
- last_page, org_hash_value, key);
-
- // Falls der Eintrag einen anderen ersetzt, so
- // ist keine Erweiterung notwendig
- if (nec_local_depth == ht_entry.local_depth)
- self.insert_in_page_list(ct, key_based_on_equal, list_cursor,
- ht_entry.page_list_offset, org_hash_value,
- key, info, pred, succ);
- else
- { if (increase_ht_structur
- (list_cursor,
- self.get_global_depth(),self.get_ht_entries(),
- self.get_no_of_pages(),self.get_cardinality(),
- ht_entry.local_depth, nec_local_depth))
- { // Die Hash-Struktur wird vergroessert, erweitere
- // zuerst die Hashtabelle auf die benoetigten Groesse
- for (;self.get_global_depth() < nec_local_depth;)
- self.increase_hash_table(); // veraendert get_global_depth() !
- // Teile jetzt die Seiten. Hierbei sind alle Seitenteilungen
- // ohne Objektumschaufelungen verbunden, bis auf die letzte.
- // Drum der Parameter nec_local_depth
- self.split_page (ct, list_cursor,
- ht_entry.page_list_offset, ht_entry.local_depth,
- org_hash_value, nec_local_depth);
-
- ht_pos = org_hash_value MOD self.get_ht_entries();
- ht_entry = read_ht_entry(ct,self.get_ht_offset(), ht_pos);
- self.insert_in_page_list (ct, key_based_on_equal, list_cursor,
- ht_entry.page_list_offset,
- org_hash_value, key, info,
- pred, succ);
- }
- else
- { // Die Seitenliste wird um eine Seite erweitert:
- increase_page_list(list_cursor, ct, ht_entry.page_list_offset,
- page_header, last_page);
- self.set_no_of_pages(self.get_no_of_pages()+1);
-
- self.insert_in_page_list(ct, key_based_on_equal, list_cursor,
- ht_entry.page_list_offset,org_hash_value,
- key, info, pred, succ);
- }
- }
- }
- TT (agg_M,T_LEAVE);
- } // ** Mapping:insert_in_list **
-
- // remove_from_page_list__30_sos_Object_sos_Object_MappingR12sos_Typed_idG13sos_Container8sos_BoolT3UiiG10sos_Object
- // **************************************************************************
- sos_Object sos_Object_sos_Object_Mapping::remove_from_page_list
- (sos_Container ct,
- sos_Bool list_cursor,
- sos_Bool key_based_on_equal,
- sos_Offset page_list_offset,
- sos_Int org_hash_value,
- sos_Object key)
- // **************************************************************************
- // Liefert sos_Bool_Object::TRUE, falls der Eintrag gefunden wurde. Der Entry
- // wird nicht geliefert, da er sonst mit make_Object angefasst werden muesste,
- // was er hier nicht soll.
- { T_PROC("Mapping::remove_from_page_list");
- TT(agg_M, T_ENTER);
-
- sos_Object my_no_object = self;
- // assume that key won't be found:
- sos_Object found = make_sos_Bool_object(FALSE);
- page_t page;
- page_header_t page_header;
- sos_Offset page_offset = page_list_offset;
- sos_Offset prev_page_offset;
- page_header = read_page_header(ct, page_offset);
- sos_Int pages = page_header.pages;
- sos_Int entries_on_last_page = page_header.entries_on_last_page;
- sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
- sos_Int page_no = 1;
- sos_Int pos = -1; // entspricht "nicht gefunden";
- for (; (page_no<=pages) AND (pos == -1); page_no++)
- { if (page_no == pages)
- entries_on_page = entries_on_last_page;
- read_page(list_cursor, ct, page_offset, entries_on_page, page);
- pos = search_page_for_key (key_based_on_equal, page,
- entries_on_page,
- org_hash_value,key);
- if (pos == -1)
- { prev_page_offset = page_offset;
- page_offset = page.page_header.next_page;
- }
- }
-
- page_no --;
- // Im Falle von based_on_equal == TRUE ist der key nicht unbedingt
- // derselbe wie der tatsaechlich eingetragene Schluessel. real_key
- // ist der Eingetragene. real_key ist fuer den Test auf Identitaet
- // mit dem ersten bzw. letzten Element notwendig.(Equal ginge auch,
- // dauert aber laenger).
- sos_Object real_key;
-
- if (pos != -1)
- { found = make_sos_Bool_object(TRUE);
- real_key = make_Object(page.entry[pos].key);
-
- sos_Object pred,succ;
- if (list_cursor)
- { pred = make_Object(page.list[pos].pred);
- succ = make_Object(page.list[pos].succ);
- }
- self.set_cardinality(self.get_cardinality() - 1);
-
- // Der zu loeschende Eintrag ist auf der letzten Seite
- if (page_no == page_header.pages)
- { // fuelle die Luecke auf
- if (page_header.entries_on_last_page > 1)
- { // und korrigiere den Seitenheader
- page.entry[pos] = page.entry[--page_header.entries_on_last_page];
- page.list[pos] = page.list[page_header.entries_on_last_page];
- // schreibe Seiteneintrag zurueck
- write_page_entry(list_cursor, ct, page_offset, pos, page);
- }
- else
- // oder deallokiere die Seite
- { if (page_header.pages > 1)
- { ct.deallocate(page_offset, PAGE_SIZE(list_cursor));
- page_header.pages --;
- page_header.entries_on_last_page=MAX_PAGE_ENTRIES(list_cursor);
- self.set_no_of_pages(self.get_no_of_pages()-1);
- }
- else
- page_header.entries_on_last_page = 0;
- }
- // schreibe Seitenheader zurueck
- write_page_header(ct,page_list_offset, page_header);
- }
- else
- { // Falls der Eintrag nicht auf der letzten Seite war, so nimm
- // einen Eintrag der letzten Seite und schreibe ihn in die Luecke
- // hangel dich zur letzten Seite vor
- sos_Offset last_page_offset = page.page_header.next_page;
- page_header_t tmp_page_header;
- page_no++;
- for (;page_no<page_header.pages;page_no++)
- { tmp_page_header = read_page_header(ct, last_page_offset);
- last_page_offset = tmp_page_header.next_page;
- }
-
- // nimm von der letzten Seite den letzten Eintrag
- // und korrigiere nur den Seitenheader
- page_t tmp_page;
- read_page_entry(list_cursor, ct,last_page_offset,
- --page_header.entries_on_last_page,
- tmp_page);
-
- // und fuege ihn in die Luecke
- page.entry[pos] = tmp_page.entry[page_header.entries_on_last_page];
- page.list[pos] = tmp_page.list[page_header.entries_on_last_page];
-
- write_page(list_cursor, ct,page_offset, pos+1, page);
-
- // Falls die letzte Seite jetzt leer ist, deallokiere
- if (page_header.entries_on_last_page == 0)
- { ct.deallocate(last_page_offset, PAGE_SIZE(list_cursor));
- page_header.entries_on_last_page = MAX_PAGE_ENTRIES(list_cursor);
- page_header.pages--;
- self.set_no_of_pages(self.get_no_of_pages()-1);
- }
-
- // Schreibe den Seitenheader der ersten Seite zurueck
- write_page_header(ct,page_list_offset, page_header);
- }
-
- if (list_cursor)
- { // fuege Objekt aus der Liste
- self.write_succ_pred
- (ct, key_based_on_equal, list_cursor, pred, TRUE, succ);
- self.write_succ_pred
- (ct, key_based_on_equal, list_cursor, succ, FALSE, pred);
-
- if (real_key == self.get_last_object())
- self.set_last_object(pred);
- if (real_key == self.get_first_object())
- self.set_first_object(succ);
-
- // Letztes Objekt:
- if (self.get_cardinality() == 0)
- { sos_Object my_no_object = self;
- self.set_first_object(my_no_object);
- self.set_last_object(my_no_object);
- }
- }
- }
-
- TT(agg_M, T_LEAVE);
- return found;
- } // ** Mapping::remove_from_page_list **
-
-
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::assemble_page(
- sos_Offset page_list_offset,
- sos_Char local_depth,
- sos_Int org_hash_value)
- // **************************************************************************
- { T_PROC("Mapping::assemble_page");
- TT(agg_M, T_ENTER);
-
- sos_Container ct = self.container();
- sos_Bool list_cursor = self.get_list_cursor();
- sos_Int max_page_entries = MAX_PAGE_ENTRIES(list_cursor);
-
- page_t page;
- page_t partner_page;
- ht_entry_t ht_partner_entry;
-
- page.page_header = read_page_header(ct, page_list_offset);
- sos_Int ht_partner_pos;
-
- sos_Bool assemble_flag;
- // liefere zurueck, ob verschmolzen wurde
- sos_Bool result = FALSE;
- sos_Bool act_page_is_read = FALSE;
-
- do // while (assemble_flag)
- { assemble_flag = FALSE;
-
- // zuerst eine Grob-Pruefung, ob eine Chance auf
- // Verschmelzung besteht:
- // Ist die Seitenliste nur eine Seite, und ist sie nur 3/4 voll,
- // und gibt es ueberhaupt eine Partnerseite ?
- if ((page.page_header.entries_on_last_page <= max_page_entries*3/4) AND
- (page.page_header.pages == 1) AND
- (local_depth > 0))
- { // Berechne die Position der Partnerseite
- ht_partner_pos = (org_hash_value BITAND LSHIFT(1,local_depth)-1)
- BITXOR LSHIFT(1,local_depth-1);
-
- // Lese den HT-Eintrag der Partnerseite
- ht_partner_entry =
- read_ht_entry(ct,self.get_ht_offset(),ht_partner_pos);
-
- // Hat die Partnerseite die gleiche lokale Tiefe ?
- if (ht_partner_entry.local_depth == local_depth)
- { // Ja
- // Lese Seitenkopf der Partner Seite
- partner_page.page_header =
- read_page_header(ct, ht_partner_entry.page_list_offset);
-
- // Besteht die Partnerseite auch nur aus einer Seite ?
- if (partner_page.page_header.pages == 1)
- { // passen alle Eintraege gut auf eine Seite ? (gut = 25% frei)
- assemble_flag = FALSE;
- if ((partner_page.page_header.entries_on_last_page+
- page.page_header.entries_on_last_page)
- <= max_page_entries*3/4)
- assemble_flag = TRUE;
- }
- }
- }
-
- if (assemble_flag)
- { result = TRUE;
-
- self.set_no_of_page_lists(self.get_no_of_page_lists() - 1);
-
- if (NOT (act_page_is_read))
- { read_page(list_cursor, ct,page_list_offset,
- page.page_header.entries_on_last_page, page);
- act_page_is_read = TRUE;
- }
-
- // Lese Partner-Seite
- read_page(list_cursor, ct,ht_partner_entry.page_list_offset,
- partner_page.page_header.entries_on_last_page,
- partner_page);
-
- // Kopiere die Eintraege der Partnerseite
- // auf die urspruengliche Seite
- for (sos_Int i=0; i<partner_page.page_header.entries_on_last_page;i++)
- { page.entry[page.page_header.entries_on_last_page] =
- partner_page.entry[i];
- page.list[page.page_header.entries_on_last_page++] =
- partner_page.list[i];
- }
-
- // Korrigiere die Angabe, wieviel Seiten mit einer
- // bestimmten lokalen Tiefe existieren
- sos_Int no_of_pages_offset = self.get_no_of_pages_offset();
- add_no_of_pages(ct,no_of_pages_offset,local_depth,-2);
- add_no_of_pages(ct,no_of_pages_offset,local_depth-1,1);
-
- // Gib die Partnerseite frei
- ct.deallocate (ht_partner_entry.page_list_offset,
- PAGE_SIZE(list_cursor));
- self.set_no_of_pages(self.get_no_of_pages()-1);
-
- write_page(list_cursor, ct,page_list_offset,
- page.page_header.entries_on_last_page, page);
-
- sos_Int old_local_depth = local_depth --;
-
- // Die Hashtabelle muss korrigiert werden: Alle
- // Verweise auf die Partnerseite muessen auf die verschmolzene
- // Seite umgebogen werden
- // Wie lautet der der vereinigten Seite zugeordnete Hashwertteil ?
- sos_Int hash_value_part = ht_partner_pos BITAND
- (LSHIFT(1,local_depth)-1);
-
- // Laufe alle Indexe durch, die auf die neue
- // vereinigte Seite zeigen. Diese Verweise werden
- // umgebogen
- sos_Int global_depth = self.get_global_depth();
- sos_Offset ht_offset = self.get_ht_offset();
- for (sos_Int k = 0;k<LSHIFT(1,global_depth-local_depth); k++)
- { // verschiebe Laufindex k an richtige Position
- // vor dem Wert der Seite
- sos_Int j = LSHIFT(k,local_depth);
- // addiere hash-Teil der Seite dazu
- j = j BITOR hash_value_part;
-
- // Dieser Eintrag muss auf die neue Seite umgebogen werden
- // d.h. vielleicht zeigt er schon auf die Seite, aber
- // die lokale Tiefe ist in jedem Fall zu hoch
- ht_entry_t ht_entry;
- ht_entry.page_list_offset = page_list_offset;
- ht_entry.local_depth = local_depth;
- write_ht_entry(ct,ht_offset,j, ht_entry);
- }
- }
- }
- while (assemble_flag);
-
- TT(agg_M,T_LEAVE);
- return result;
- } // ** Mapping::assemble_page **
-
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::decrease_hash_table()
- // **************************************************************************
- // die Hash-tabelle kann genau dann halbiert werden, wenn
- // keine Seiten existieren, die nur einen Verweis in der
- // Hash-Tabelle besitzen
- {
- T_PROC("Mapping::decrease_hash_table");
- TT(agg_M, T_ENTER);
-
- sos_Container ct = self.container();
- sos_Int global_depth = self.get_global_depth();
- sos_Offset no_of_pages_offset = self.get_no_of_pages_offset();
-
- for (;no_single_referenced_pages(ct,no_of_pages_offset,global_depth);)
- { // Merke alte Tabellen-Position und Laenge
- sos_Int old_ht_entries = self.get_ht_entries();
- sos_Int old_ht_size = old_ht_entries*HT_ENTRY_SIZE;
- sos_Offset old_ht_offset = self.get_ht_offset();
-
- // definiere neue Tabellen Position und Laenge
- sos_Int new_ht_entries = old_ht_entries / 2;
- sos_Int new_ht_size = new_ht_entries*HT_ENTRY_SIZE;
- sos_Int new_ht_offset = ct.allocate(new_ht_entries*HT_ENTRY_SIZE);
- self.set_ht_entries(new_ht_entries);
- self.set_ht_offset(new_ht_offset);
-
- // kopiere erste Haelfte der alten Tabelle in neue Tabelle
- ct.copy( old_ht_offset,new_ht_size,ct,new_ht_offset);
- global_depth--;
-
- // Gib alte Tabelle frei
- ct.deallocate(old_ht_offset,old_ht_size);
- }
- self.set_global_depth(global_depth);
- TT (agg_M,T_LEAVE);
- } // ** decrease_hash_table
-
- // **************************************************************************
- sos_Bool get_entry (sos_Container ct,
- sos_Bool list_cursor,
- sos_Bool key_based_on_equal,
- sos_Int ht_entries,
- sos_Offset ht_offset,
- sos_Object& key,
- sos_Bool return_info,
- sos_Object& info,
- sos_Object& pred,
- sos_Object& succ)
- // **************************************************************************
- // Setzt key und - falls list_cursor == TRUE - pred und succ auf die
- // key-Objekte im gegebenen Mapping. Ergebnis ist das dem key entsprechende
- // info. Es gilt agg_same_entity (key-vorher, key-nachher, key_based_on_equal)
- // Wird return_info== TRUE uebergeben, wird info geliefert, ansonsten nicht.
- // pred und succ werden nur im Falle von list_cursor == TRUE geliefert.
-
- { T_PROC("get_entry");
- TT(agg_M,T_ENTER; TI(ht_entries); TI(ht_offset));
-
- if (ht_entries>0)
- { sos_Int org_hash_value = absolute((key_based_on_equal)?
- key.hash_value() : hash_id(key));
- sos_Int ht_pos = org_hash_value MOD ht_entries;
- ht_entry_t ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
- page_t page;
-
- sos_Offset page_offset = ht_entry.page_list_offset;
- sos_Int pos = -1; // entspricht "nicht gefunden"
-
- page_header_t page_header = read_page_header (ct, page_offset);
- sos_Int pages = page_header.pages;
- sos_Int entries_on_last_page = page_header.entries_on_last_page;
- sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
- for (sos_Int page_no = 1; (page_no<=pages) AND (pos == -1); page_no++)
- { if (page_no == pages)
- entries_on_page = entries_on_last_page;
-
- read_page(list_cursor, ct, page_offset, entries_on_page, page);
- pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
- org_hash_value, key );
- if (pos == -1)
- page_offset = page.page_header.next_page;
- else
- { if (list_cursor)
- { pred = make_Object(page.list[pos].pred);
- succ = make_Object(page.list[pos].succ);
- sos_Bool test1 = (succ == NO_OBJECT);
- sos_Bool test2 = (pred == NO_OBJECT);
- }
- key = make_Object(page.entry[pos].key);
- if (return_info)
- info = make_Object(page.entry[pos].info);
-
- TT(agg_M, T_LEAVE);
- // gefunden !
- return TRUE;
- }
- }
- }
- TT(agg_M,T_LEAVE);
- // nicht gefunden:
- return FALSE;
- } // ** get_entry **
-
- /*
- Reihenfolge in der Hashtabelle:
- Die Ordnung bezieht sich immer nur auf diejenigen Verweise in der Hashtabelle,
- die die ersten Verweise auf eine bestimmte Seitenliste sind. Das Durchlaufen
- mit einem Cursor funktioniert auf der Version mit list_cursor == FALSE so:
- Die Cursor-Operatoren wurden ueberlagert, mit dem Oeffnen eines Cursors werden
- die Prozeduren read_first_object und read_last_object aufgerufen, die das
- erste und letzte Objekt liefern. open_cursor setzt nun die Variablen
- first_object und last_object. Beim Durchlaufen mit dem Cursor wird die
- Hashtabelle solange durchsucht, bis ein Verweis gefunden wird, der der Erste
- auf die referenzierte Seitenliste ist. Dies ist der Fall, wenn in der Position
- der Hashtabelle (ht_pos) nur die ersten (lokale_tiefe) Bit gesetzt sind. Auf
- der Seitenliste werden die Eintraege gemaess der Reihenfolge auf der Seite
- durchlaufen. Nach dem letzten Eintrag auf der Seitenliste beginnt wieder die
- Suche in der Hashtabelle nach einem ersten Verweis auf die naechste
- Seitenliste.
- */
-
- // **************************************************************************
- sos_Object get_pred ( sos_Container ct,
- sos_Bool key_based_on_equal,
- sos_Object my_no_object,
- sos_Int ht_entries,
- sos_Offset ht_offset,
- sos_Object key)
- // **************************************************************************
- // Diese Prozedur wird nur aufgerufen, wenn get_list_cursor() == FALSE,
- // d.h. die Version ohne verkettung der Eintraege ist gefragt.
- // Es wird das Objekt in der eben geschilderten Reihenfolge nach key
- // geliefert.
- { sos_Int org_hash_value =absolute((key_based_on_equal)?
- key.hash_value() : hash_id(key));
- sos_Int ht_pos = org_hash_value MOD ht_entries;
- sos_Object result;
-
- ht_entry_t ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
- page_t page;
- sos_Int first_link = FIRST_LINK(ht_pos, ht_entry.local_depth);
- ht_pos = first_link;
- sos_Offset page_offset = ht_entry.page_list_offset;
-
- page_header_t page_header = read_page_header (ct, page_offset);
- sos_Int pages = page_header.pages;
- sos_Int entries_on_last_page = page_header.entries_on_last_page;
- sos_Int entries_on_page = max_page_entries_without_list;
- result = my_no_object;
- sos_Int pos = -1; // entspricht "nicht gefunden"
- for (sos_Int page_no = 1;
- (page_no<=pages) AND (pos == -1);
- page_no++)
- { if (page_no == pages)
- entries_on_page = entries_on_last_page;
-
- read_page(FALSE, ct, page_offset, entries_on_page, page);
- pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
- org_hash_value, key );
- if (pos == -1)
- { page_offset = page.page_header.next_page;
- result = make_Object(page.entry[entries_on_page-1].key);
- }
- else
- { // Findet sich der Vorgaenger auf derselben Seite ?
- if (pos > 0)
- result = make_Object(page.entry[pos-1].key);
- else
- { // Falls eine vorherige Seite in der seitenliste
- // existiert, so wurde ihr letzter Eintrag in
- // result bereits gesetzt. Ist es jedoch die erste Seite
- // muss auf eine vorherige Seitenliste gegangen werden
- if (page_no == 1)
- { sos_Bool found = FALSE;
- do
- { ht_pos--;
- do
- { if (ht_pos >= 0)
- { // suche den naechsten ersten verweis ab ht_pos;
- ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
- first_link = FIRST_LINK(ht_pos, ht_entry.local_depth);
-
- if (first_link != ht_pos)
- ht_pos--;
- }
- } while ((first_link != ht_pos) AND (ht_pos >= 0));
-
- if (ht_pos >= 0)
- { page_header =
- read_page_header(ct,ht_entry.page_list_offset);
-
- // Falls auf dieser Seitenliste ein
- // Eintrag ist, lese ihn, sonst bleibt found == FALSE
- if ((page_header.pages > 1) OR
- (page_header.entries_on_last_page > 0))
- { found = TRUE;
- // lese letzte Seite
- sos_Int i = read_page(FALSE, ct,page_header, ht_entry,
- page_header.pages, page);
- result = make_Object(page.entry[i-1].key);
- }
- }
- } while ((NOT found) AND (ht_pos >= 0));
- }
- }
- }
- }
-
- return result;
- } // ** get_pred **
-
- // **************************************************************************
- sos_Object get_succ ( sos_Container ct,
- sos_Bool key_based_on_equal,
- sos_Object my_no_object,
- sos_Int ht_entries,
- sos_Offset ht_offset,
- sos_Object key)
- // **************************************************************************
- { sos_Int org_hash_value = absolute((key_based_on_equal)?
- key.hash_value() : hash_id(key));
- sos_Int ht_pos = org_hash_value MOD ht_entries;
- sos_Object result;
-
- ht_entry_t ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
- page_t page;
- sos_Int first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
- ht_pos = first_link;
- sos_Offset page_offset = ht_entry.page_list_offset;
-
- page_header_t page_header = read_page_header (ct, page_offset);
- sos_Int pages = page_header.pages;
- sos_Int entries_on_last_page = page_header.entries_on_last_page;
- sos_Int entries_on_page = max_page_entries_without_list;
- result = my_no_object;
- sos_Int pos = -1; // entspricht "nicht gefunden"
- for (sos_Int page_no = 1; (page_no<=pages) AND (pos == -1); page_no++)
- { if (page_no == pages)
- entries_on_page = entries_on_last_page;
-
- read_page(FALSE, ct, page_offset, entries_on_page, page);
- pos = search_page_for_key ( key_based_on_equal, page, entries_on_page,
- org_hash_value, key );
- if (pos == -1)
- page_offset = page.page_header.next_page;
- else
- { // Findet sich der Nachfolger auf derselben Seite ?
- if (pos < entries_on_page-1)
- result = make_Object(page.entry[pos+1].key);
- else
- { if (page_no < page_header.pages)
- { read_page(FALSE, ct, page.page_header.next_page, 1, page);
- result = make_Object(page.entry[0].key);
- }
- else
- { // Der Schluessel ist der letzte Eintrag auf der
- // Seitenliste, der Nachfolger ist auf der
- // naechsten Seitenliste
- sos_Bool found = FALSE;
- do
- { ht_pos++;
- do
- { // suche den naechsten ersten verweis ab ht_pos;
- // read ht_entry
- if (ht_pos < ht_entries)
- { ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
- first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
- if (first_link != ht_pos)
- ht_pos++;
- }
- } while ((first_link != ht_pos) AND (ht_pos < ht_entries));
-
- if (ht_pos < ht_entries)
- { // lese den Seitenkopf und das erste
- // Objekt dieser Seite
- read_page(FALSE,ct, ht_entry.page_list_offset, 1, page);
- if ((page.page_header.pages > 1) OR
- (page.page_header.entries_on_last_page > 0))
- { found = TRUE;
- result = make_Object(page.entry[0].key);
- }
- }
- } while ((NOT found) AND (ht_pos < ht_entries));
- }
- }
- }
- }
-
- return result;
- } // ** Mapping::get_succ **
-
-
- // **************************************************************************
- sos_Object sos_Object_sos_Object_Mapping::search_succ_pred
- (sos_Object key, sos_Int steps)
- // **************************************************************************
- { T_PROC("Mapping::search_succ_pred");
- TT(agg_M, T_ENTER; TI (steps));
-
- sos_Container ct = self.container();
- sos_Bool key_based_on_equal = self.get_key_based_on_equal();
- sos_Bool list_cursor = self.get_list_cursor();
- sos_Object my_no_object = self;
- sos_Int ht_entries = self.get_ht_entries();
- sos_Offset ht_offset = self.get_ht_offset();
- sos_Object dummy_info; // wird in get_entry nicht angefasst
-
- for (;steps != 0;)
- { sos_Object pred,succ;
- if (list_cursor)
- { get_entry(ct, list_cursor, key_based_on_equal,
- ht_entries,ht_offset,
- key, FALSE, dummy_info, pred,succ);
- if (steps > 0)
- { if (succ == my_no_object)
- { TT(agg_M, T_LEAVE);
- return my_no_object;
- }
- key = succ;
- steps--;
- }
- else
- { if (pred == my_no_object)
- { TT(agg_M, T_LEAVE);
- return my_no_object;
- }
- key = pred;
- steps++;
- }
- }
- else
- { if (steps > 0)
- { succ = get_succ(ct,key_based_on_equal,my_no_object,
- ht_entries,ht_offset,key);
- if (succ == my_no_object)
- { TT(agg_M, T_LEAVE);
- return my_no_object;
- }
- key = succ;
- steps--;
- }
- else
- { pred = get_pred(ct,key_based_on_equal,my_no_object,
- ht_entries,ht_offset,key);
- if (pred == my_no_object)
- { TT(agg_M, T_LEAVE);
- return my_no_object;
- }
- key = pred;
- steps++;
- }
- }
- }
- TT(agg_M,T_LEAVE);
- return key;
- } // ** Mapping::search_succ_pred **
-
-
- // **************************************************************************
- sos_Object read_last_object(sos_Container ct,
- sos_Offset ht_offset,
- sos_Int length,
- sos_Object my_no_object,
- sos_Int ht_entries)
- // **************************************************************************
- { sos_Int ht_pos = ht_entries-1;
- sos_Bool found = FALSE;
- if (length == 0)
- return my_no_object;
- sos_Object result;
- ht_entry_t ht_entry;
- page_t page;
- page_header_t page_header;
- sos_Int first_link;
- do
- { do
- { // suche den vorherigen ersten Verweis ab ht_pos rueckwaerts
- ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
- first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
- if (first_link != ht_pos)
- ht_pos--;
- } while (first_link != ht_pos);
-
- // lese den page_header um festzustellen, ob auf der
- // Seitenliste ein Objekt ist
- page_header = read_page_header(ct,ht_entry.page_list_offset);
- if ((page_header.pages > 1) OR
- (page_header.entries_on_last_page > 0))
- { found = TRUE;
- // lese letzte Seite
- read_page(FALSE,ct ,page_header, ht_entry, page_header.pages, page);
- result=make_Object(page.entry[page_header.entries_on_last_page-1].key);
- }
- else
- ht_pos--;
- } while (NOT found);
-
- return result;
- } // ** Mapping::read_last_object **
-
- // **************************************************************************
- sos_Object read_first_object(sos_Container ct,
- sos_Offset ht_offset,
- sos_Int length,
- sos_Object my_no_object)
- // **************************************************************************
- { sos_Int ht_pos = 0;
- sos_Bool found = FALSE;
- if (length == 0)
- return my_no_object;
- sos_Object result;
- ht_entry_t ht_entry;
- page_t page;
- sos_Int first_link;
-
- do
- { do
- { // suche den naechsten ersten verweis ab ht_pos;
- // read ht_entry
- ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
- first_link = FIRST_LINK(ht_pos,ht_entry.local_depth);
- if (first_link != ht_pos)
- ht_pos++;
- }
- while (first_link != ht_pos);
-
- // lese die Seite und das erste Objekt von diesem Verweis
- read_page(FALSE, ct, ht_entry.page_list_offset, 1, page);
- if ((page.page_header.pages > 1) OR
- (page.page_header.entries_on_last_page > 0))
- { found = TRUE;
- result = make_Object(page.entry[0].key);
- }
- else
- ht_pos++;
- } while (NOT found);
- return result;
- } // ** Mapping::read_first_object **
-
-
- // **************************************************************************
- void destroy_ht (sos_Bool list_cursor,
- sos_Container ct,
- sos_Int ht_entries,
- sos_Int global_depth,
- sos_Offset ht_offset)
- // **************************************************************************
- { T_PROC("destroy_ht ");
- TT (agg_M, T_ENTER; TI(ht_entries); TI(global_depth));
- // loescht alle Eintrage und die Hashtabelle,
-
- ht_entry_t ht_entry;
-
- for (sos_Int ht_pos=0;ht_pos < ht_entries;ht_pos++)
- { ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
- sos_Int local_depth = ht_entry.local_depth;
- // Berechne denjenigen Teil des Hashwertes, der auf der
- // Seitenliste unterschieden wird, dies ist gleichzeitig
- // der erste Verweis auf die Seitenliste
- sos_Int hash_value_part = FIRST_LINK(ht_pos, local_depth);
-
- // Berechne den letzten Verweis auf diese Seiteliste
- sos_Int last_link = LSHIFT(LSHIFT(1,global_depth-local_depth)-1,
- local_depth) BITAND hash_value_part;
- // es muss der letzte Verweis sein, andernfalls wuerde die Kiste
- // beim nachfolgenden Lesen der lokalen Tiefe abschmieren,
- // da die Seite schon deallokiert waere.
-
- // Falls der gefundendene Verweis der letzte auf diese Seitenliste
- // ist, so deallokiere diese
- if (last_link == ht_pos)
- { page_header_t page_header =
- read_page_header(ct,ht_entry.page_list_offset);
- destroy_page_list(list_cursor, ct,
- ht_entry.page_list_offset, page_header.pages);
- }
- }
-
- if (ht_entries>0)
- ct.deallocate(ht_offset,ht_entries*HT_ENTRY_SIZE);
-
- TT(agg_M,T_LEAVE);
- } // ** Mapping::destroy_ht **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::init_table ()
- // **************************************************************************
- { T_PROC("Mapping::init_table");
- TT(agg_H, T_ENTER);
-
- // create a hash-tab
- // Ein Eintrag besteht aus einem Offset
- // also einem Zeiger auf eine Seite
- self.set_ht_entries(1);
- sos_Container ct = self.container();
- self.set_ht_offset(ct.allocate (self.get_ht_entries()*HT_ENTRY_SIZE));
-
- // no_of_pages[i] gibt an, wieviel Seiten mit der lokalen
- // Tiefe i existieren
- self.set_no_of_pages_offset(ct.allocate(NO_OF_PAGES_ARRAY_SIZE));
- sos_Char mem [NO_OF_PAGES_ARRAY_SIZE];
- for (sos_Int i = 0;i< NO_OF_PAGES_ARRAY_SIZE;i++) mem[i] = 0;
- ct.write(self.get_no_of_pages_offset(), NO_OF_PAGES_ARRAY_SIZE, &mem);
-
- ht_entry_t ht_entry;
- ht_entry.page_list_offset = ct.allocate(PAGE_SIZE(self.get_list_cursor()));
- ht_entry.local_depth = 0;
- write_ht_entry(ct, self.get_ht_offset(),0,ht_entry);
-
- page_header_t page_header;
- page_header.pages = 1;
- page_header.entries_on_last_page = 0;
- write_page_header(ct,ht_entry.page_list_offset,page_header);
-
- self.set_no_of_pages(1);
- self.set_no_of_page_lists(1);
- add_no_of_pages(ct,self.get_no_of_pages_offset(),0,1);
-
- TT(agg_H,T_LEAVE);
- } // ** Mapping::init_table **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::local_initialize
- (sos_Object_sos_Object_Mapping map)
- // **************************************************************************
- { T_PROC("Mapping::local_initialize");
- TT(agg_H, T_ENTER);
-
- sos_Object my_no_object = map;
-
- map.set_cardinality (0);
- map.set_first_object(my_no_object);
- map.set_last_object(my_no_object);
- map.set_ht_entries(0);
- map.set_global_depth(0);
- map.set_no_of_pages_offset(NIL);
- map.set_no_of_pages(0);
- map.set_ht_offset(NIL);
-
- TT(agg_H,T_LEAVE);
- }; // ** Mapping::local_initialize **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::local_finalize
- (sos_Object_sos_Object_Mapping map)
- // **************************************************************************
- { T_PROC("Mapping::local_finalize");
- TT (agg_H, T_ENTER);
-
- destroy_ht(map.get_list_cursor(), map.container(), map.get_ht_entries(),
- map.get_global_depth(), map.get_ht_offset());
-
- TT (agg_H, T_LEAVE);
- } // ** Mapping::local_finalize **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::is_key (sos_Object key)
- // **************************************************************************
- { T_PROC("Mapping::is_key");
- TT(agg_H, T_ENTER);
- sos_Object dummy_pred,dummy_succ,dummy_info;
- sos_Bool result = FALSE;
- sos_Object my_no_object = self;
- result = get_entry(self.container(), self.get_list_cursor(),
- self.get_key_based_on_equal(),
- self.get_ht_entries(), self.get_ht_offset(),
- key, FALSE, dummy_info, dummy_pred,dummy_succ);
- TT(agg_H, T_LEAVE);
- return result;
- } // ** Mapping::is_key **
-
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::is_info (sos_Object info)
- // **************************************************************************
- // TRUE, falls info mit insert(*,info) in die Struktur
- // aufgenommen wurde.
- // Vorsicht !! nicht aufrufen !!
- // Die Funktion hat einen Aufwand von o(Anzahl der Eintraege) !!
- { T_PROC("Mapping::is_info");
- TT(agg_H,T_ENTER);
-
- sos_Container ct = self.container();
- sos_Bool list_cursor = self.get_list_cursor();
- sos_Bool info_based_on_equal = self.get_info_based_on_equal();
- ht_entry_t ht_entry;
- page_t page;
- sos_Object key;
-
- // Durchlaufe die gesamte Hashtabelle
- // benutze jeden Verweis um die Seite zu durchsuchen,
- // verwende bei mehrfachen Verweisen nur den ersten
- sos_Int ht_entries = self.get_ht_entries();
- sos_Offset ht_offset = self.get_ht_offset();
- for (sos_Int ht_pos=0;
- ht_pos < ht_entries; // positiver Abbruch nur in der Schleife
- ht_pos++)
- { ht_entry = read_ht_entry(ct,ht_offset,ht_pos);
-
- // Wie lautet der dieser Seite zugeordnete Hash-Wert ?
- sos_Int hash_value_part = (LSHIFT(1,ht_entry.local_depth)-1)
- BITAND ht_pos;
-
- // Ist dieser Verweis der erste auf diese Seite ?
- if (hash_value_part == ht_pos)
- { // Ja,
- sos_Offset page_offset = ht_entry.page_list_offset;
- page_header_t page_header = read_page_header(ct, page_offset);
-
- sos_Bool found = FALSE;
- sos_Int pages = page_header.pages;
- sos_Int entries_on_last_page = page_header.entries_on_last_page;
- sos_Int entries_on_page = MAX_PAGE_ENTRIES(list_cursor);
- for (sos_Int page_no = 1;
- (page_no<=pages) AND (NOT found);
- page_no++)
- { if (page_no == pages)
- entries_on_page = entries_on_last_page;
-
- if (entries_on_page > 0)
- read_page(list_cursor, ct,page_offset,
- entries_on_page, page);
-
- // Durchsuche die Seite nach dem Objekt
- for (sos_Int k=0;
- (NOT found) AND (k<entries_on_page);
- k++)
- { key = make_Object(page.entry[k].info);
- found = agg_same_entity (key,info,info_based_on_equal,EQ_STRONG);
- }
-
- if (found)
- { TT(agg_H,T_LEAVE);
- return TRUE;
- }
-
- page_offset = page.page_header.next_page;
- }
- }
- }
-
- TT(agg_H,T_LEAVE);
- return FALSE; // Pech ...
- } // ** Mapping::is_info **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::insert(sos_Object Key, sos_Object Entity)
- // **************************************************************************
- { T_PROC("Mapping::insert");
- TT(agg_H, T_ENTER);
-
- sos_Object my_no_object = self;
- // Das Mappingobjekt selbst wird als Methodenausgabe fuer ein ungueltiges
- // Objekt benutzt. Drum kann man NO_OBJECT, aber nicht das
- // Mappingobjekt einfuegen. Soll es auch auch eingefuegt werden koennen,
- // benoetigt man ein eigenes MAPPING_NO_OBJECT.
- if (Key == self)
- err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
-
- // fuege das Element in der Listen-Version hinten an die Liste
- // in der non-Listen Version haben die beiden letzten Parameter
- // pred und succ keine Wirkung
- self.insert_in_list(Key, Entity, self.get_last_object(), my_no_object);
-
- TT(agg_H,T_LEAVE);
- } // ** Mapping::insert **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::remove (sos_Object key)
- // **************************************************************************
- { T_PROC("Mapping::remove");
-
- sos_Bool found=FALSE;
-
- if (self.get_ht_entries() >0)
- { sos_Container ct = self.container();
- sos_Int org_hash_value = absolute((self.get_key_based_on_equal())?
- key.hash_value():hash_id(key));
- sos_Int ht_pos = org_hash_value MOD self.get_ht_entries();
- ht_entry_t ht_entry = read_ht_entry(ct,self.get_ht_offset(),ht_pos);
- found = make_sos_Bool(
- self.remove_from_page_list (ct, self.get_list_cursor(),
- self.get_key_based_on_equal(),
- ht_entry.page_list_offset,
- org_hash_value,key));
- sos_Object my_no_object = self;
- if (found)
- { // Versuche, die Seitenliste zu verschmelzen
- if (self.assemble_page(ht_entry.page_list_offset,
- ht_entry.local_depth,
- org_hash_value))
- // versuche, die Hash-Tabelle zu verkleinern
- self.decrease_hash_table();
- }
- }
- TT(agg_H,T_LEAVE; TB(found));
- }// ** Mapping::remove **
-
- // **************************************************************************
- sos_Object sos_Object_sos_Object_Mapping::operator[] (sos_Object key)
- // **************************************************************************
- { T_PROC("Mapping::operator[]");
- TT(agg_H,T_ENTER);
-
- sos_Object dummy_pred,dummy_succ,info;
- sos_Container ct = self.container();
- sos_Bool key_based_on_equal = self.get_key_based_on_equal();
- sos_Bool list_cursor = self.get_list_cursor();
- sos_Object my_no_object = self;
- sos_Int ht_entries = self.get_ht_entries();
- sos_Offset ht_offset = self.get_ht_offset();
-
- if (NOT get_entry(ct, list_cursor,key_based_on_equal,ht_entries,
- ht_offset,key,TRUE, info, dummy_pred,dummy_succ))
- info = NO_OBJECT;
-
- TT(agg_H,T_LEAVE);
- return info;
- } // ** Mapping::operator[] **
-
- // **************************************************************************
- sos_Object sos_Object_sos_Object_Mapping::get_key(sos_Cursor c)
- // **************************************************************************
- { T_PROC("Mapping::get_key(sos_Cursor)");
- TT(agg_H, T_ENTER);
-
- err_assert (c.defined_for (self), "Mapping:get_key");
- err_assert (self.is_valid(c), "Mapping:get_key");
-
- sos_Map_node mn = sos_Map_node::make (c.get_current());
- sos_Object o = mn.get_key_val();
-
- TT(agg_H,T_LEAVE);
- return o;
- } // ** Mapping::get_key **
-
- // **************************************************************************
- sos_Object sos_Object_sos_Object_Mapping::get_info(sos_Cursor c)
- // **************************************************************************
- { T_PROC("Mapping::get_info(sos_Cursor)");
- TT(agg_H, T_ENTER);
-
- err_assert (c.defined_for (self), "Mapping:get_info");
- err_assert(self.is_valid(c),"Mapping:get_info");
-
- sos_Object my_no_object = self;
- sos_Object dummy_pred,
- dummy_succ;
-
- sos_Object key = sos_Map_node::make (c.get_current()).get_key_val();
- sos_Object info;
- sos_Bool found = get_entry(self.container(), self.get_list_cursor(),
- self.get_key_based_on_equal(),
- self.get_ht_entries(), self.get_ht_offset(),
- key,TRUE, info,dummy_pred,dummy_succ);
- // Beliebter Benutzerfehler: Ein Prozess erzeugt
- // einen Eintrag mit einem Key im TEMP_CONTAINER, das
- // Programm beendet, ein anderer Prozess versucht darueber
- // zu itterieren. Trotz das im Key Bockmist steht, kann er
- // noch mit get_key geliefert werden. Wenn jedoch der passende Eintrag
- // dazu gesucht wird, wird der Hashwert vom Key gebraucht. In diesem
- // stehen wilde Sachen, der Eintrag wird (vermutlich) nicht gefunden.
- if (NOT found)
- err_raise(err_USE,"Entry didn't exists anymore","Mapping::get_info");
-
- TT(agg_H, T_LEAVE);
- return info;
- } // ** Mapping::get_info **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::set_info(sos_Cursor c, sos_Object o)
- // **************************************************************************
- { T_PROC ("Mapping::set_info");
- TT (agg_H, T_ENTER);
-
- err_assert ((c.defined_for (self)), "Mapping:set_info");
- self.insert (sos_Map_node::make (c.get_current()).get_key_val(), o);
-
- TT (agg_H, T_LEAVE);
- } // ** Mapping::set_info **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::move_cursor(sos_Cursor c, sos_Object key)
- // **************************************************************************
- // sets the cursor c to the key object in the mapping that corresponds
- // to the given key
- { T_PROC ("Mapping::move_cursor");
- TT( agg_H, T_ENTER);
-
- err_assert (c.defined_for (self), "Mapping:move_cursor");
- err_assert (self.is_key(key), "Mapping:move_cursor");
-
- sos_Object dummy_pred, dummy_succ, dummy_info;
- sos_Bool found = get_entry(self.container(), self.get_list_cursor(),
- self.get_key_based_on_equal(),
- self.get_ht_entries(),self.get_ht_offset(),
- key,FALSE, dummy_info, dummy_pred,dummy_succ);
- err_assert (found, "Mapping:move_cursor");
- sos_Map_node::make (c.get_current()).set_key_val(key);
-
- TT(agg_H, T_LEAVE);
- } // ** Mapping::move_cursor **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::insert_before (sos_Cursor c,
- sos_Object Key,
- sos_Object Entity)
- // **************************************************************************
- { T_PROC("Mapping::insert_before");
- TT(agg_H, T_ENTER);
-
- err_assert (self.get_list_cursor(), "Mapping:insert_before");
- err_assert (c.defined_for (self), "Mapping:insert_before");
- err_assert (self.is_valid(c), "Mapping:insert_before");
-
- if (Key == self)
- err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
- sos_Map_node mn = sos_Map_node::make (c.get_current());
-
- sos_Object dummy_info,pred,dummy_succ;
- sos_Object key = mn.get_key_val();
- get_entry(self.container(), self.get_list_cursor(),
- self.get_key_based_on_equal(),
- self.get_ht_entries(),self.get_ht_offset(),
- key,FALSE, dummy_info, pred,dummy_succ);
- self.insert_in_list(Key, Entity, pred, mn.get_key_val());
-
- TT(agg_H, T_LEAVE);
- } // ** Mapping::insert_before **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::insert_after (sos_Cursor c,
- sos_Object Key,
- sos_Object Entity)
- // **************************************************************************
- { T_PROC("Mapping::insert_after");
- TT(agg_H, T_ENTER);
-
- err_assert (self.get_list_cursor(), "Mapping:insert_after");
- err_assert (c.defined_for (self), "Mapping:insert_after");
- err_assert (self.is_valid(c), "Mapping:insert_after");
-
- if (Key == self)
- err_raise(err_USE,"Mapping itself cannot inserted","Mapping::insert");
-
- sos_Map_node mn = sos_Map_node::make (c.get_current());
-
- sos_Object dummy_info,dummy_pred,succ;
- sos_Object key = mn.get_key_val();
- get_entry(self.container(), self.get_list_cursor(),
- self.get_key_based_on_equal(),
- self.get_ht_entries(),self.get_ht_offset(),
- key,FALSE,dummy_info,dummy_pred,succ);
- self.insert_in_list(Key, Entity, mn.get_key_val(), succ);
-
- TT(agg_H, T_LEAVE);
- } // ** Mapping::insert_after **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::local_assign
- (sos_Object_sos_Object_Mapping x,
- sos_Object o)
- // **************************************************************************
- { T_PROC("Mapping::local_assign");
-
- sos_Object_sos_Object_Mapping y = sos_Object_sos_Object_Mapping::make (o);
- sos_Container y_ct = y.container();
- sos_Container x_ct = x.container();
- sos_Bool x_list_cursor = x.get_list_cursor();
-
- err_assert ((y.get_list_cursor() == x_list_cursor),
- "Mapping::local_assign");
-
- destroy_ht(x_list_cursor, x_ct, x.get_ht_entries(),
- x.get_global_depth(), x.get_ht_offset());
-
- sos_Bool key_based_on_equal = y.get_key_based_on_equal();
- sos_Bool info_based_on_equal= y.get_info_based_on_equal();
- sos_Int cardinality = y.get_cardinality();
- sos_Int no_of_pages = y.get_no_of_pages();
- sos_Int no_of_page_lists = y.get_no_of_page_lists();
- sos_Int global_depth = y.get_global_depth();
- sos_Int ht_entries = y.get_ht_entries();
- sos_Int no_of_pages_offset = y.get_no_of_pages_offset();
-
- x.set_key_based_on_equal(key_based_on_equal);
- x.set_info_based_on_equal(info_based_on_equal);
- x.set_cardinality(cardinality);
- x.set_no_of_pages(no_of_pages);
- x.set_no_of_page_lists(no_of_page_lists);
- x.set_global_depth(global_depth);
- x.set_ht_entries(ht_entries);
- x.set_first_object(y.get_first_object());
- x.set_last_object(y.get_last_object());
-
-
- if (cardinality != 0)
- { // kopiere das Feld fuer no_of_pages rueber
- sos_Offset new_no_of_pages_offset = x_ct.allocate(NO_OF_PAGES_ARRAY_SIZE);
- x.set_no_of_pages_offset(new_no_of_pages_offset);
- sos_Char mem [NO_OF_PAGES_ARRAY_SIZE];
- y_ct.read(no_of_pages_offset, NO_OF_PAGES_ARRAY_SIZE, &mem);
- x_ct.write(new_no_of_pages_offset, NO_OF_PAGES_ARRAY_SIZE, &mem);
-
- // erzeuge die Hashtabelle
- x.set_ht_offset(x_ct.allocate(y.get_ht_entries() *HT_ENTRY_SIZE));
- // Laufe die erste HT durch und kopiere die Seiten
- sos_Offset old_ht_offset = y.get_ht_offset();
- sos_Offset new_ht_offset = x.get_ht_offset();
- for (sos_Int ht_pos = 0;ht_pos<y.get_ht_entries();ht_pos++)
- { ht_entry_t ht_entry = read_ht_entry(y_ct,old_ht_offset,ht_pos);
-
- // Ist es der erste Zeiger auf die Seitenliste ?
- sos_Int local_depth = ht_entry.local_depth;
- sos_Int first_link = FIRST_LINK(ht_pos, local_depth);
- if (first_link == ht_pos)
- { // erster Verweis, kopiere die Seitenliste
- sos_Offset old_page_offset = ht_entry.page_list_offset;
- page_header_t old_first_page_header =
- read_page_header(y_ct, ht_entry.page_list_offset);
-
- sos_Offset pred_page_offset=0;
-
- for(sos_Int page_no=1;page_no<=old_first_page_header.pages;page_no++)
- { sos_Offset new_page_offset =
- x_ct.allocate(PAGE_SIZE(x_list_cursor));
- if (page_no == 1)
- ht_entry.page_list_offset = new_page_offset;
- else
- { page_header_t tmp_page_header = old_first_page_header;
- tmp_page_header.next_page = new_page_offset;
- // schreibe den Seitenverweis in den Vorgaenger
- write_page_header(x_ct,pred_page_offset, tmp_page_header);
- }
-
- page_t tmp_page;
- sos_Int entries = (page_no < old_first_page_header.pages)?
- MAX_PAGE_ENTRIES(x_list_cursor):
- old_first_page_header.entries_on_last_page;
-
- // kopiere die Seite
- read_page(x_list_cursor,y_ct,old_page_offset,entries,tmp_page);
- write_page(x_list_cursor, x_ct,new_page_offset,
- MAX_PAGE_ENTRIES(x_list_cursor), tmp_page);
- pred_page_offset = new_page_offset;
-
- // lese den Seitenkopf der Seite, um
- // Nachfolgerseite rauszufinden
- page_header_t old_page_header =
- read_page_header(y_ct,old_page_offset);
-
- old_page_offset = old_page_header.next_page;
- } // kopiere alle Seiten
-
- // schreibe den HT-Eintrag in alle Verweise der HT
- sos_Int no_of_links = LSHIFT(1,global_depth-local_depth);
- for (sos_Int k=0;k<no_of_links;k++)
- { sos_Int x = LSHIFT(k,local_depth);
- sos_Int other_link = x BITOR ht_pos;
- write_ht_entry(x_ct,new_ht_offset,other_link,ht_entry);
- } // schreibe alle HT-Eintraege pro Seite
- }
- }
- if (x_list_cursor)
- { sos_Object my_no_object = x;
- x.write_succ_pred
- (x_ct, key_based_on_equal, x_list_cursor,
- x.get_first_object(), FALSE, my_no_object);
- x.write_succ_pred
- (x_ct, key_based_on_equal, x_list_cursor,
- x.get_last_object(), TRUE, my_no_object);
- }
- }
- else
- { // Kein Element drin, erzeuge nichts, initialisere wie in local_init
- sos_Object my_no_object = x;
- x.set_first_object(my_no_object);
- x.set_last_object(my_no_object);
- x.set_ht_offset(NIL);
- x.set_ht_entries(0);
- x.set_no_of_pages_offset(NIL);
- }
-
- TT(agg_H,T_LEAVE);
- } // ** Mapping::local_assign **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::local_equal
- (sos_Object_sos_Object_Mapping x,
- sos_Object o,
- sos_Eq_kind eq_kind)
- // **************************************************************************
- { sos_Bool result;
-
- if ((eq_kind EQ EQ_STRONG AND NOT o.has_type(x.type())) OR
- (eq_kind EQ EQ_WEAK AND NOT o.isa (x.type())))
- result = FALSE;
- else
- { sos_Object_sos_Object_Mapping y =
- sos_Object_sos_Object_Mapping::make (o);
- if (y.get_cardinality() != x.get_cardinality())
- result = FALSE;
- else
- { sos_Bool info_based_on_equal = x.get_info_based_on_equal();
- agg_iterate_association (x, sos_Object key, sos_Object info)
- { if (NOT agg_same_entity (y[key],info,info_based_on_equal,eq_kind))
- { result = FALSE;
- break;
- }
- }
- agg_iterate_association_end (x, key, info);
- }
- }
-
- return result;
- } // ** Mapping::local_equal **
-
- // **************************************************************************
- sos_Int sos_Object_sos_Object_Mapping::local_hash_value
- (sos_Object_sos_Object_Mapping m)
- // **************************************************************************
- // Ansich muesste der augenblickliche Hashwert gespeichert werden, und bei
- // jedem eingefuegten Element mit einer reversiblen Operation verknuepft
- // werden. Bei jedem remove, muss diese reversible Operation aufgerufen
- // werden. Zu viel Aufwand, drum bisher noch nicht implementiert.
- { return m.card();
- } // ** Mapping::local_hash_value **
-
- // **************************************************************************
- sos_Int sos_Object_sos_Object_Mapping::size()
- // **************************************************************************
- { sos_Int o_size = sos_Object::size();
- sos_Int ht_size = self.get_ht_entries() * HT_ENTRY_SIZE;
- sos_Int nop_size = (ht_size>0)?NO_OF_PAGES_ARRAY_SIZE:0;
- sos_Int pg_size = self.get_no_of_pages()*PAGE_SIZE(self.get_list_cursor());
- return o_size +
- self.container().rounded (ht_size) +
- self.container().rounded (pg_size) +
- self.container().rounded (nop_size);
- } // ** Mapping::size **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::is_role1 (sos_Object key)
- // **************************************************************************
- { return self.is_key (key);
- } // ** Mapping::is_role1 **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::is_role2 (sos_Object info)
- // **************************************************************************
- { return self.is_info (info);
- } // ** Mapping::is_role2 **
-
- // **************************************************************************
- sos_Object sos_Object_sos_Object_Mapping::get_role1 (sos_Cursor c)
- // **************************************************************************
- { return self.get_key (c);
- } // ** Mapping::get_role1 **
-
- // **************************************************************************
- sos_Object sos_Object_sos_Object_Mapping::get_role2 (sos_Cursor c)
- // **************************************************************************
- { return self.get_info (c);
- } // ** Mapping::get_role2 **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::remove_at(sos_Cursor c)
- // **************************************************************************
- { T_PROC("Mapping::remove_at");
- TT(agg_H, T_ENTER);
-
- err_assert (c.defined_for (self), "Mapping:remove_at");
- err_assert (self.is_valid(c), "Mapping:remove_at");
-
- sos_Object key = self.get_key(c);
-
- if (self.get_list_cursor())
- self.to_succ(c);
- else
- { // Setze Cursor auf my_no_object => is_valid == FALSE
- sos_Object my_no_object = self;
- sos_Map_node mn = sos_Map_node::make (c.get_current());
- mn.set_key_val(my_no_object);
- }
-
- self.remove(key);
-
- TT(agg_H, T_LEAVE);
- } // ** Mapping::remove_at **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::clear()
- // **************************************************************************
- { T_PROC("Mapping::clear");
- TT(agg_H, T_ENTER);
-
- sos_Container ct = self.container();
- sos_Int ht_entries = self.get_ht_entries();
- if (ht_entries >0)
- destroy_ht(self.get_list_cursor(), ct, ht_entries,
- self.get_global_depth(), self.get_ht_offset());
-
- sos_Object my_no_object = self;
- self.set_first_object(my_no_object);
- self.set_last_object(my_no_object);
- self.set_cardinality (0);
- self.set_ht_entries(0);
- self.set_global_depth(0);
- self.set_no_of_pages_offset(NIL);
- self.set_no_of_pages(0);
- self.set_ht_offset(NIL);
-
- TT(agg_H, T_LEAVE);
- } // ** Mapping::clear **
-
- // **************************************************************************
- sos_Int sos_Object_sos_Object_Mapping::card ()
- // **************************************************************************
- { T_PROC ("Mapping::card");
- TT (agg_H, T_ENTER);
-
- sos_Int crd = self.get_cardinality();
-
- TT (agg_H, T_LEAVE);
- return crd;
- } // ** Mapping::card **
-
- // **************************************************************************
- sos_Cursor sos_Object_sos_Object_Mapping::open_cursor(sos_Container Cursor_ct)
- // **************************************************************************
- { T_PROC ("Mapping::open_cursor");
- TT( agg_H, T_ENTER);
-
- sos_Cursor c = sos_Cursor::create(Cursor_ct, self);
- sos_Map_node mn = sos_Map_node::create(Cursor_ct);
- c.set_current(mn);
-
- self.to_first(c);
-
- TT(agg_H, T_LEAVE);
- return c;
- } // ** Mapping::open_cursor **
-
- // **************************************************************************
- void sos_Object_sos_Object_Mapping::close_cursor(sos_Cursor c)
- // **************************************************************************
- { err_assert ((c.defined_for (self)), "Mapping:close_cursor");
- c.get_current().destroy();
- c.destroy();
- } // ** Mapping::close_cursor **
-
- // **************************************************************************
- sos_Cursor sos_Object_sos_Object_Mapping::duplicate(sos_Cursor c)
- // **************************************************************************
- { err_assert ((c.defined_for (self)), "Mapping:duplicate");
- sos_Container Cursor_ct = c.container();
-
- sos_Cursor dup_c = sos_Cursor::create(Cursor_ct, self);
- sos_Map_node dup_mn = sos_Map_node::create(Cursor_ct);
-
- dup_c.set_current (dup_mn);
- dup_mn.set_key_val (sos_Map_node::make (c.get_current()).get_key_val());
-
- return dup_c;
- } // ** Mapping::duplicate **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::is_valid (sos_Cursor c)
- // **************************************************************************
- { sos_Map_node mn = sos_Map_node::make (c.get_current());
- sos_Object my_no_object = self;
- sos_Bool valid = (mn.get_key_val() != my_no_object);
-
- return valid;
- } // ** is_valid **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::to_first(sos_Cursor c)
- // **************************************************************************
- { err_assert ((c.defined_for (self)), "Mapping:to_first");
- sos_Container Cursor_ct = c.container();
- sos_Map_node current = sos_Map_node::make (c.get_current());
- sos_Object my_no_object = self;
- sos_Object first;
-
- if (self.get_cardinality() > 0)
- { if (NOT (self.get_list_cursor()))
- first = read_first_object(self.container(),self.get_ht_offset(),
- self.get_cardinality(),my_no_object);
- else
- first = self.get_first_object();
- }
- else
- first = my_no_object;
-
- current.set_key_val(first);
-
- return self.is_valid(c);
- } // ** Mapping::to_first **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::to_last(sos_Cursor c)
- // **************************************************************************
- { err_assert ((c.defined_for (self)), "Mapping:to_last");
- sos_Map_node current = sos_Map_node::make (c.get_current());
- sos_Container Cursor_ct = c.container();
- sos_Object my_no_object = self;
- sos_Object last;
-
- if (self.get_cardinality() > 0)
- { if (NOT (self.get_list_cursor()))
- last = read_last_object
- (self.container(),
- self.get_ht_offset(),self.get_cardinality(),
- my_no_object,self.get_ht_entries());
- else
- last = self.get_last_object();
- }
- else
- last = my_no_object;
-
- current.set_key_val(last);
-
- return self.is_valid(c);
- } // ** Mapping::to_last **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::to_succ(sos_Cursor c, Index i)
- // **************************************************************************
- { err_assert (c.defined_for (self), "Mapping:to_succ");
- err_assert (self.is_valid(c), "Mapping:to_succ");
-
- sos_Map_node mn = sos_Map_node::make (c.get_current());
- sos_Object o = self.search_succ_pred (mn.get_key_val(),i);
-
- mn.set_key_val (o);
-
- return self.is_valid (c);
- } // ** Mapping::to_succ **
-
- // **************************************************************************
- sos_Bool sos_Object_sos_Object_Mapping::to_pred(sos_Cursor c, Index i)
- // **************************************************************************
- { return self.to_succ(c,-i);
- } // ** Mapping::to_pred **
-